1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
|
# umoci: Umoci Modifies Open Containers' Images
# Copyright (C) 2016-2020 SUSE LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Use bash, so that we can do process substitution.
SHELL := $(shell which bash)
# Go tools.
GO ?= go
GO_MD2MAN ?= go-md2man
GOOS ?= $(shell go env GOOS)
GOARCH ?= $(shell go env GOARCH)
export GO111MODULE=on
# Set up the ... lovely ... GOPATH hacks.
PROJECT := github.com/opencontainers/umoci
CMD := ${PROJECT}/cmd/umoci
# We use Docker because Go is just horrific to deal with.
UMOCI_IMAGE := umoci/ci:latest
# TODO: We should test umoci with all of the security options disabled so that
# we can make sure umoci inside containers works fine (all of these
# security options are necessary for the test code to run, not umoci
# itself). The AppArmor/SELinux settings are needed because of the
# mount-related tests, and the seccomp/systempaths settings are required
# for the runc tests for rootless containers.
DOCKER_RUN = docker run --rm -v ${PWD}:/go/src/${PROJECT} \
--security-opt apparmor=unconfined \
--security-opt label=disable \
--security-opt seccomp=unconfined \
--security-opt systempaths=unconfined
# We only add the CodeCov environment (and ping codecov) if we're running in
# Travis, to avoid pinging third-party servers for local builds.
ifdef TRAVIS
$(shell echo "WARNING: This make invocation will fetch and run code from https://codecov.io/." >&2)
DOCKER_RUN += $(shell echo "+ curl -sSL https://codecov.io/env | bash" >&2) \
$(shell ./hack/resilient-curl.sh -sSL https://codecov.io/env | bash)
endif
DOCKER_ROOTPRIV_RUN = $(DOCKER_RUN) --privileged --cap-add=SYS_ADMIN
DOCKER_ROOTLESS_RUN = $(DOCKER_RUN) -u 1000:1000 --cap-drop=all
# Output directory.
BUILD_DIR ?= .
# Release information.
GPG_KEYID ?=
# Version information.
VERSION := $(shell cat ./VERSION)
COMMIT_NO := $(shell git rev-parse HEAD 2> /dev/null || true)
COMMIT := $(if $(shell git status --porcelain --untracked-files=no),"${COMMIT_NO}-dirty","${COMMIT_NO}")
# Basic build flags.
BUILD_FLAGS ?=
BASE_FLAGS := ${BUILD_FLAGS} -tags "${BUILDTAGS}"
BASE_LDFLAGS := -s -w -X ${PROJECT}.gitCommit=${COMMIT} -X ${PROJECT}.version=${VERSION}
# Specific build flags for build type.
ifeq ($(GOOS), linux)
TEST_BUILD_FLAGS := ${BASE_FLAGS} -buildmode=pie -ldflags "${BASE_LDFLAGS} -X ${PROJECT}/pkg/testutils.binaryType=test" DYN_BUILD_FLAGS := ${BASE_FLAGS} -buildmode=pie -ldflags "${BASE_LDFLAGS}"
TEST_BUILD_FLAGS := ${BASE_FLAGS} -buildmode=pie -ldflags "${BASE_LDFLAGS} -X ${PROJECT}/pkg/testutils.binaryType=test"
else
DYN_BUILD_FLAGS := ${BASE_FLAGS} -ldflags "${BASE_LDFLAGS}"
TEST_BUILD_FLAGS := ${BASE_FLAGS} -ldflags "${BASE_LDFLAGS} -X ${PROJECT}/pkg/testutils.binaryType=test"
endif
STATIC_BUILD_FLAGS := ${BASE_FLAGS} -ldflags "${BASE_LDFLAGS} -extldflags '-static'"
# Installation directories.
DESTDIR ?=
PREFIX ?=/usr/local
BINDIR ?=$(PREFIX)/bin
MANDIR ?=$(PREFIX)/share/man
.DEFAULT: umoci
GO_SRC = $(shell find . -type f -name '*.go')
# NOTE: If you change these make sure you also update local-validate-build.
umoci: $(GO_SRC)
GOOS=$(GOOS) GOARCH=$(GOARCH) $(GO) build ${DYN_BUILD_FLAGS} -o $(BUILD_DIR)/$@ ${CMD}
umoci.static: $(GO_SRC)
env CGO_ENABLED=0 $(GO) build ${STATIC_BUILD_FLAGS} -o $(BUILD_DIR)/$@ ${CMD}
.PHONY: static
static: umoci.static
umoci.cover: $(GO_SRC)
$(GO) test -c -cover -covermode=count -coverpkg=./... ${TEST_BUILD_FLAGS} -o $(BUILD_DIR)/$@ ${CMD}
.PHONY: release
release:
hack/release.sh -v $(VERSION) -S "$(GPG_KEYID)"
.PHONY: install
install: umoci docs
install -D -m0755 umoci $(DESTDIR)/$(BINDIR)/umoci
-for man in $(MANPAGES); do \
filename="$$(basename -- "$$man")"; \
target="$(DESTDIR)/$(MANDIR)/man$${filename##*.}/$$filename"; \
install -D -m0644 "$$man" "$$target"; \
gzip -9f "$$target"; \
done
.PHONY: uninstall
uninstall:
rm -f $(DESTDIR)/$(BINDIR)/umoci
-rm -f $(DESTDIR)/$(MANDIR)/man*/umoci*
.PHONY: clean
clean:
rm -f umoci umoci.static umoci-ci.tar umoci.cov*
rm -f $(MANPAGES)
.PHONY: validate
validate: ci-image
$(DOCKER_RUN) $(UMOCI_IMAGE) make local-validate
.PHONY: local-validate
local-validate: local-validate-go local-validate-spell local-validate-reproducible local-validate-build
.PHONY: local-validate-go
local-validate-go:
@type gofmt >/dev/null 2>/dev/null || (echo "ERROR: gofmt not found." && false)
test -z "$$(gofmt -s -l . | grep -vE '^vendor/|^third_party/' | tee /dev/stderr)"
@type golint >/dev/null 2>/dev/null || (echo "ERROR: golint not found." && false)
test -z "$$(golint $(PROJECT)/... | grep -vE '/vendor/|/third_party/' | tee /dev/stderr)"
@go doc cmd/vet >/dev/null 2>/dev/null || (echo "ERROR: go vet not found." && false)
test -z "$$($(GO) vet $$($(GO) list $(PROJECT)/... | grep -vE '/vendor/|/third_party/') 2>&1 | tee /dev/stderr)"
@type gosec >/dev/null 2>/dev/null || (echo "ERROR: gosec not found." && false)
test -z "$$(gosec -quiet -exclude=G301,G302,G304 $$GOPATH/$(PROJECT)/... | tee /dev/stderr)"
./hack/test-vendor.sh
.PHONY: local-validate-spell
local-validate-spell:
make clean
@type misspell >/dev/null 2>/dev/null || (echo "ERROR: misspell not found." && false)
test -z "$$(find . -type f -print0 | xargs -0 misspell | grep -vE '/(vendor|third_party|\.site)/' | tee /dev/stderr)"
# Make sure that our builds are reproducible even if you wait between them and
# the modified time of the files is different.
.PHONY: local-validate-reproducible
local-validate-reproducible:
mkdir -p .tmp-validate
make -B umoci && cp umoci .tmp-validate/umoci.a
@echo sleep 10s
@sleep 10s && touch $(GO_SRC)
make -B umoci && cp umoci .tmp-validate/umoci.b
diff -s .tmp-validate/umoci.{a,b}
sha256sum .tmp-validate/umoci.{a,b}
rm -r .tmp-validate/umoci.{a,b}
.PHONY: local-validate-build
local-validate-build:
$(GO) build ${DYN_BUILD_FLAGS} -o /dev/null ${CMD}
env CGO_ENABLED=0 $(GO) build ${STATIC_BUILD_FLAGS} -o /dev/null ${CMD}
$(GO) test -run nothing ${DYN_BUILD_FLAGS} $(PROJECT)/...
MANPAGES_MD := $(wildcard doc/man/*.md)
MANPAGES := $(MANPAGES_MD:%.md=%)
doc/man/%.1: doc/man/%.1.md
$(GO_MD2MAN) -in $< -out $@
.PHONY: docs
docs: $(MANPAGES)
# Used for tests.
DOCKER_IMAGE ?=registry.opensuse.org/opensuse/leap:latest
ifndef COVERAGE
COVERAGE := $(notdir $(shell mktemp -u umoci.cov.XXXXXX))
endif
export COVERAGE
.PHONY: test-unit
test-unit: ci-image
touch $(COVERAGE) && chmod a+rw $(COVERAGE)
$(DOCKER_ROOTPRIV_RUN) -e COVERAGE $(UMOCI_IMAGE) make local-test-unit
$(DOCKER_ROOTLESS_RUN) -e COVERAGE $(UMOCI_IMAGE) make local-test-unit
.PHONY: local-test-unit
local-test-unit:
GO=$(GO) hack/test-unit.sh
.PHONY: test-integration
test-integration: ci-image
touch $(COVERAGE) && chmod a+rw $(COVERAGE)
$(DOCKER_ROOTPRIV_RUN) -e COVERAGE -e TESTS $(UMOCI_IMAGE) make local-test-integration
$(DOCKER_ROOTLESS_RUN) -e COVERAGE -e TESTS $(UMOCI_IMAGE) make local-test-integration
.PHONY: local-test-integration
local-test-integration: umoci.cover
TESTS="${TESTS}" hack/test-integration.sh
.PHONY: shell
shell: ci-image
$(DOCKER_RUN) -it $(UMOCI_IMAGE) bash
.PHONY: root-shell
root-shell: ci-image
$(DOCKER_ROOTPRIV_RUN) -it $(UMOCI_IMAGE) bash
.PHONY: rootless-shell
rootless-shell: ci-image
$(DOCKER_ROOTLESS_RUN) -it $(UMOCI_IMAGE) bash
CACHE := .cache
CACHE_IMAGE := $(CACHE)/ci-image.tar.zst
.PHONY: ci-image
ci-image:
docker pull registry.opensuse.org/opensuse/leap:latest
! [ -f "$(CACHE_IMAGE)" ] || unzstd < "$(CACHE_IMAGE)" | docker load
DOCKER_BUILDKIT=1 docker build -t $(UMOCI_IMAGE) \
--progress plain \
--cache-from $(UMOCI_IMAGE) \
--build-arg DOCKER_IMAGE=$(DOCKER_IMAGE) \
--build-arg BUILDKIT_INLINE_CACHE=1 .
.PHONY: ci-cache
ci-cache: ci-image
rm -rf $(CACHE) && mkdir -p $(CACHE)
docker save $(UMOCI_IMAGE) | zstd > $(CACHE_IMAGE)
.PHONY: ci-validate
ci-validate: umoci umoci.static
make docs local-validate
.PHONY: ci-unit
ci-unit: umoci.cover
make test-unit
.PHONY: ci-integration
ci-integration: umoci.cover
make test-integration
.PHONY: ci
ci:
@echo "NOTE: This is not identical to the upstream CI, but the tests are the same."
make ci-validate ci-unit ci-integration
hack/ci-coverage.sh $(COVERAGE)
|