From 7f9dac569750c6c00fc0124223b5225729c1c079 Mon Sep 17 00:00:00 2001 From: Ramkumar Chinchani Date: Mon, 5 Dec 2022 21:13:54 +0000 Subject: [PATCH 01/10] test: add code coverage support With golang 1.20.x, we can build a binary with coverage support. " Cover Go 1.20 supports collecting code coverage profiles for programs (applications and integration tests), as opposed to just unit tests. To collect coverage data for a program, build it with go build's -cover flag, then run the resulting binary with the environment variable GOCOVERDIR set to an output directory for coverage profiles. See the 'coverage for integration tests' landing page for more on how to get started. For details on the design and implementation, see the proposal. " Signed-off-by: Ramkumar Chinchani --- .github/workflows/build.yaml | 2 +- .github/workflows/ci.yaml | 9 ++++++ .github/workflows/coverage.yaml | 56 +++++++++++++++++++++++++++++++++ Makefile | 28 ++++++++++++++--- build.yaml | 6 +++- 5 files changed, 95 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/coverage.yaml diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index f5d599a06..c5d1f1337 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -31,7 +31,7 @@ jobs: uses: actions/setup-go@v3 with: go-version: ${{ matrix.go-version }} - - name: install dependencies + - name: Install dependencies run: | sudo apt-get update sudo apt-get install -yy lxc-utils lxc-dev libacl1-dev jq libcap-dev libseccomp-dev libpam-dev bats parallel libzstd-dev diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3ade24199..7986fe444 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -18,3 +18,12 @@ jobs: ["1.20.x"] privilege-level: >- ["unpriv", "priv"] + coverage: + uses: ./.github/workflows/coverage.yaml + with: + # note >-, args needs to be strings to be used as inputs + # for the reusable build.yaml workflow + go-version: >- + ["1.20.x"] + privilege-level: >- + ["unpriv", "priv"] diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml new file mode 100644 index 000000000..8982ad7a9 --- /dev/null +++ b/.github/workflows/coverage.yaml @@ -0,0 +1,56 @@ +name: Reusable stacker build for coverage +on: + workflow_call: + inputs: + go-version: + required: true + type: string + description: 'Stringified JSON object listing go versions' + privilege-level: + required: true + type: string + description: 'Stringified JSON object listing stacker privilege-level' +jobs: + build: + runs-on: ubuntu-22.04 + services: + registry: + image: registry:2 + ports: + - 5000:5000 + strategy: + matrix: + go-version: ${{fromJson(inputs.go-version)}} + privilege-level: ${{fromJson(inputs.privilege-level)}} + name: "golang ${{ matrix.go-version }} privilege ${{ matrix.privilege-level }}" + steps: + - uses: actions/checkout@v3 + - uses: benjlevesque/short-sha@v2.1 + id: short-sha + - name: Set up golang ${{ matrix.go-version }} + uses: actions/setup-go@v3 + with: + go-version: ${{ matrix.go-version }} + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -yy lxc-utils lxc-dev libacl1-dev jq libcap-dev libseccomp-dev libpam-dev bats parallel libzstd-dev + GO111MODULE=off go get github.com/opencontainers/umoci/cmd/umoci + sudo cp ~/go/bin/umoci /usr/bin + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin + sudo apt-get install -yy autoconf automake make autogen autoconf libtool binutils git squashfs-tools libcryptsetup-dev libdevmapper-dev cryptsetup-bin squashfuse + (cd /tmp && git clone https://github.com/AgentD/squashfs-tools-ng && cd squashfs-tools-ng && ./autogen.sh && ./configure --prefix=/usr && make -j2 && sudo make -j2 install && sudo ldconfig -v) + (cd /tmp && git clone https://github.com/anuvu/squashfs && cd squashfs && make && sudo cp squashtool/squashtool /usr/bin) + - if: github.event_name != 'release' || github.event.action != 'published' + name: Build and test + run: | + export GOCOVERDIR=. + make check-cov PRIVILEGE_LEVEL=${{ matrix.privilege-level }} + go tool covdata textfmt -i $GOCOVERDIR -o coverage-${{ matrix.privilege-level }}.txt + go tool covdata percent -i $GOCOVERDIR + env: + REGISTRY_URL: localhost:5000 + - name: Upload code coverage + uses: codecov/codecov-action@v3 + with: + files: coverage-${{ matrix.privilege-level}}.txt diff --git a/Makefile b/Makefile index 66fa3dfea..4c30d2629 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ BUILD_TAGS = exclude_graphdriver_btrfs exclude_graphdriver_devicemapper containe STACKER_OPTS=--oci-dir=.build/oci --roots-dir=.build/roots --stacker-dir=.build/stacker --storage-type=overlay -build_stacker = go build -tags "$(BUILD_TAGS) $1" -ldflags "-X main.version=$(VERSION_FULL) -X main.lxc_version=$(LXC_VERSION) $2" -o $3 ./cmd/stacker +build_stacker = go build $1 -tags "$(BUILD_TAGS) $2" -ldflags "-X main.version=$(VERSION_FULL) -X main.lxc_version=$(LXC_VERSION) $3" -o $4 ./cmd/stacker STACKER_DOCKER_BASE?=docker:// STACKER_BUILD_BASE_IMAGE?=$(STACKER_DOCKER_BASE)alpine:edge @@ -23,15 +23,30 @@ stacker: stacker-dynamic --substitute STACKER_BUILD_BASE_IMAGE=$(STACKER_BUILD_BASE_IMAGE) \ --substitute LXC_CLONE_URL=$(LXC_CLONE_URL) \ --substitute LXC_BRANCH=$(LXC_BRANCH) \ - --substitute VERSION_FULL=$(VERSION_FULL) + --substitute VERSION_FULL=$(VERSION_FULL) \ + --substitute WITH_COV=no + +stacker-cov: stacker-dynamic + ./stacker-dynamic --debug $(STACKER_OPTS) build \ + -f build.yaml --shell-fail \ + --substitute STACKER_BUILD_BASE_IMAGE=$(STACKER_BUILD_BASE_IMAGE) \ + --substitute LXC_CLONE_URL=$(LXC_CLONE_URL) \ + --substitute LXC_BRANCH=$(LXC_BRANCH) \ + --substitute VERSION_FULL=$(VERSION_FULL) \ + --substitute WITH_COV=yes stacker-static: $(GO_SRC) go.mod go.sum cmd/stacker/lxc-wrapper/lxc-wrapper - $(call build_stacker,static_build,-extldflags '-static',stacker) + $(call build_stacker,,static_build,-extldflags '-static',stacker) + +# can't use a comma in func call args, so do this instead +, := , +stacker-static-cov: $(GO_SRC) go.mod go.sum cmd/stacker/lxc-wrapper/lxc-wrapper + $(call build_stacker,-cover -coverpkg="./pkg/...$(,)./cmd/...",static_build,-extldflags '-static',stacker) # TODO: because we clean lxc-wrapper in the nested build, this always rebuilds. # Could find a better way to do this. stacker-dynamic: $(GO_SRC) go.mod go.sum cmd/stacker/lxc-wrapper/lxc-wrapper - $(call build_stacker,,,stacker-dynamic) + $(call build_stacker,,,,stacker-dynamic) cmd/stacker/lxc-wrapper/lxc-wrapper: cmd/stacker/lxc-wrapper/lxc-wrapper.c make -C cmd/stacker/lxc-wrapper LDFLAGS=-static LDLIBS="$(shell pkg-config --static --libs lxc) -lpthread -ldl" lxc-wrapper @@ -61,6 +76,11 @@ check: stacker lint $(shell [ -z $(PRIVILEGE_LEVEL) ] || echo --privilege-level=$(PRIVILEGE_LEVEL)) \ $(patsubst %,test/%.bats,$(TEST)) +check-cov: stacker-cov lint + sudo -E PATH="$$PATH" LXC_BRANCH="$(LXC_BRANCH)" LXC_CLONE_URL="$(LXC_CLONE_URL)" ./test/main.py \ + $(shell [ -z $(PRIVILEGE_LEVEL) ] || echo --privilege-level=$(PRIVILEGE_LEVEL)) \ + $(patsubst %,test/%.bats,$(TEST)) + .PHONY: vendorup vendorup: go get -u diff --git a/build.yaml b/build.yaml index ee75c9c14..506006c6a 100644 --- a/build.yaml +++ b/build.yaml @@ -89,4 +89,8 @@ build: export VERSION_FULL=${{VERSION_FULL}} make -C /stacker-tree/cmd/stacker/lxc-wrapper clean - make -C /stacker-tree stacker-static + if [ x${{WITH_COV}} = x"yes" ]; then + make -C /stacker-tree stacker-static-cov + else + make -C /stacker-tree stacker-static + fi From 08e1a8ab2590a2b99653fa0aae7ca4688202c206 Mon Sep 17 00:00:00 2001 From: Ramkumar Chinchani Date: Fri, 10 Feb 2023 05:02:02 +0000 Subject: [PATCH 02/10] test: list files Signed-off-by: Ramkumar Chinchani --- .github/workflows/coverage.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index 8982ad7a9..72e6c8a5e 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -46,8 +46,10 @@ jobs: run: | export GOCOVERDIR=. make check-cov PRIVILEGE_LEVEL=${{ matrix.privilege-level }} + ls -altr go tool covdata textfmt -i $GOCOVERDIR -o coverage-${{ matrix.privilege-level }}.txt go tool covdata percent -i $GOCOVERDIR + ls -altr env: REGISTRY_URL: localhost:5000 - name: Upload code coverage From e2b3f4791c59c81cb9ceca51420e33495d0f267c Mon Sep 17 00:00:00 2001 From: Ramkumar Chinchani Date: Fri, 10 Feb 2023 18:58:24 +0000 Subject: [PATCH 03/10] fix: add one more setting Signed-off-by: Ramkumar Chinchani --- .github/workflows/coverage.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index 72e6c8a5e..564fbab56 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -45,7 +45,7 @@ jobs: name: Build and test run: | export GOCOVERDIR=. - make check-cov PRIVILEGE_LEVEL=${{ matrix.privilege-level }} + make check-cov GCOVERDIR=. PRIVILEGE_LEVEL=${{ matrix.privilege-level }} ls -altr go tool covdata textfmt -i $GOCOVERDIR -o coverage-${{ matrix.privilege-level }}.txt go tool covdata percent -i $GOCOVERDIR From 98adf98604f41b24db1efe9491d7008db2342c7a Mon Sep 17 00:00:00 2001 From: Ramkumar Chinchani Date: Fri, 10 Feb 2023 20:39:38 +0000 Subject: [PATCH 04/10] fix: add environ directly Signed-off-by: Ramkumar Chinchani --- test/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/main.py b/test/main.py index c13d28106..a03719231 100755 --- a/test/main.py +++ b/test/main.py @@ -27,6 +27,7 @@ env = os.environ.copy() env["PRIVILEGE_LEVEL"] = priv + env["GOCOVERDIR"] = "." print("running tests in modes:", priv) try: From 16a9dc63f5d72a9055d59a8f34931edf0ac9e8a3 Mon Sep 17 00:00:00 2001 From: Ramkumar Chinchani Date: Fri, 10 Feb 2023 21:58:06 +0000 Subject: [PATCH 05/10] fix: pass GOCOVERDIR explicitly as environ Signed-off-by: Ramkumar Chinchani --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 4c30d2629..fc333d5d1 100644 --- a/Makefile +++ b/Makefile @@ -72,6 +72,7 @@ check: stacker lint STACKER_BUILD_BASE_IMAGE=$(STACKER_BUILD_BASE_IMAGE) \ STACKER_BUILD_CENTOS_IMAGE=$(STACKER_BUILD_CENTOS_IMAGE) \ STACKER_BUILD_UBUNTU_IMAGE=$(STACKER_BUILD_UBUNTU_IMAGE) \ + GOCOVERDIR=. \ ./test/main.py \ $(shell [ -z $(PRIVILEGE_LEVEL) ] || echo --privilege-level=$(PRIVILEGE_LEVEL)) \ $(patsubst %,test/%.bats,$(TEST)) From 831b51633bb66994bf1f049dbb4d78267215bdf9 Mon Sep 17 00:00:00 2001 From: Ramkumar Chinchani Date: Fri, 10 Feb 2023 22:45:54 +0000 Subject: [PATCH 06/10] fix: fix the Makefile Signed-off-by: Ramkumar Chinchani --- Makefile | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index fc333d5d1..43ce60e44 100644 --- a/Makefile +++ b/Makefile @@ -72,13 +72,19 @@ check: stacker lint STACKER_BUILD_BASE_IMAGE=$(STACKER_BUILD_BASE_IMAGE) \ STACKER_BUILD_CENTOS_IMAGE=$(STACKER_BUILD_CENTOS_IMAGE) \ STACKER_BUILD_UBUNTU_IMAGE=$(STACKER_BUILD_UBUNTU_IMAGE) \ - GOCOVERDIR=. \ ./test/main.py \ $(shell [ -z $(PRIVILEGE_LEVEL) ] || echo --privilege-level=$(PRIVILEGE_LEVEL)) \ $(patsubst %,test/%.bats,$(TEST)) check-cov: stacker-cov lint - sudo -E PATH="$$PATH" LXC_BRANCH="$(LXC_BRANCH)" LXC_CLONE_URL="$(LXC_CLONE_URL)" ./test/main.py \ + sudo -E PATH="$$PATH" \ + LXC_BRANCH=$(LXC_BRANCH) \ + LXC_CLONE_URL=$(LXC_CLONE_URL) \ + STACKER_BUILD_BASE_IMAGE=$(STACKER_BUILD_BASE_IMAGE) \ + STACKER_BUILD_CENTOS_IMAGE=$(STACKER_BUILD_CENTOS_IMAGE) \ + STACKER_BUILD_UBUNTU_IMAGE=$(STACKER_BUILD_UBUNTU_IMAGE) \ + GOCOVERDIR=. \ + ./test/main.py \ $(shell [ -z $(PRIVILEGE_LEVEL) ] || echo --privilege-level=$(PRIVILEGE_LEVEL)) \ $(patsubst %,test/%.bats,$(TEST)) From 176bbde913eb125510bb1b0447a417ff657ebf07 Mon Sep 17 00:00:00 2001 From: Ramkumar Chinchani Date: Fri, 10 Feb 2023 23:31:21 +0000 Subject: [PATCH 07/10] fix: aother fix Signed-off-by: Ramkumar Chinchani --- test/helpers.bash | 1 + 1 file changed, 1 insertion(+) diff --git a/test/helpers.bash b/test/helpers.bash index 9f82473fd..02b2a574a 100644 --- a/test/helpers.bash +++ b/test/helpers.bash @@ -42,6 +42,7 @@ function image_copy { STACKER_DOCKER_BASE=${STACKER_DOCKER_BASE:-docker://} STACKER_BUILD_CENTOS_IMAGE=${STACKER_BUILD_CENTOS_IMAGE:-${STACKER_DOCKER_BASE}centos:latest} STACKER_BUILD_UBUNTU_IMAGE=${STACKER_BUILD_UBUNTU_IMAGE:-${STACKER_DOCKER_BASE}ubuntu:latest} +GOCOVERDIR=${GOCOVERDIR:-.} ( flock 9 [ -f "$ROOT_DIR/test/centos/index.json" ] || (image_copy "${STACKER_BUILD_CENTOS_IMAGE}" "oci:$ROOT_DIR/test/centos:latest" && chmod -R 777 "$ROOT_DIR/test/centos") From eab2af5c6cb938845c02783d6e781881b3621e47 Mon Sep 17 00:00:00 2001 From: Ramkumar Chinchani Date: Mon, 13 Feb 2023 17:42:16 +0000 Subject: [PATCH 08/10] fix: add a env flag Signed-off-by: Ramkumar Chinchani --- pkg/stacker/build.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/stacker/build.go b/pkg/stacker/build.go index 3429effd2..1f732f885 100644 --- a/pkg/stacker/build.go +++ b/pkg/stacker/build.go @@ -609,6 +609,9 @@ func runInternalGoSubcommand(config types.StackerConfig, args []string) error { c.Stdin = os.Stdin c.Stdout = os.Stdout c.Stderr = os.Stderr + // FIXME: add coverage flag + env := []string{"GOCOVERDIR=."} + c.Env = env return errors.WithStack(c.Run()) } From 75a72b849b06b9e89afd14e53ca20359262ca4a9 Mon Sep 17 00:00:00 2001 From: Ramkumar Chinchani Date: Mon, 13 Feb 2023 19:47:10 +0000 Subject: [PATCH 09/10] fix: more fixes for unpriv Signed-off-by: Ramkumar Chinchani --- test/helpers.bash | 1 + 1 file changed, 1 insertion(+) diff --git a/test/helpers.bash b/test/helpers.bash index 02b2a574a..286621aeb 100644 --- a/test/helpers.bash +++ b/test/helpers.bash @@ -50,6 +50,7 @@ GOCOVERDIR=${GOCOVERDIR:-.} ) 9<$ROOT_DIR/test/main.py export CENTOS_OCI="$ROOT_DIR/test/centos:latest" export UBUNTU_OCI="$ROOT_DIR/test/ubuntu:latest" +export GOCOVERDIR="." function sha() { echo $(sha256sum $1 | cut -f1 -d" ") From 33bfb0398bb6c253053a116ab30fd5eae81d2568 Mon Sep 17 00:00:00 2001 From: Ramkumar Chinchani Date: Mon, 13 Feb 2023 21:39:28 +0000 Subject: [PATCH 10/10] fix: try this now Signed-off-by: Ramkumar Chinchani --- pkg/container/userns.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/container/userns.go b/pkg/container/userns.go index 25c4ce76d..151175441 100644 --- a/pkg/container/userns.go +++ b/pkg/container/userns.go @@ -26,7 +26,7 @@ func MaybeRunInNamespace(config types.StackerConfig, userCmd []string) error { cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr - cmd.Env = env + cmd.Env = append(env, "GOCOVERDIR=.") return errors.WithStack(cmd.Run()) }