diff --git a/.github/workflows/buildTests.yaml b/.github/workflows/buildTests.yaml index d223e70..2c901b0 100644 --- a/.github/workflows/buildTests.yaml +++ b/.github/workflows/buildTests.yaml @@ -1,56 +1,34 @@ -name: build tests for flannel-cni +name: build tests for flannel cni-plugin -on: [push, pull_request] - -env: - GO_VERSION: "1.15.15" - LINUX_ARCHES: "amd64 386 arm arm64 s390x mips64le ppc64le" +on: + push: + branches: + - main + pull_request: + branches: + - main jobs: - build: - name: build - runs-on: ubuntu-latest - steps: - - name: Set up Go 1.x - uses: actions/setup-go@v2 - with: - go-version: ${{ env.GO_VERSION }} - - name: Check out code into the Go module directory - uses: actions/checkout@v2 - - - name: go mod vendor - run: go mod vendor - - - name: build linux - run: | - set -e - for arch in ${LINUX_ARCHES}; do - echo "Building for arch $arch" - ARCH=$arch make build_linux - file dist/flannel-$arch - rm dist/* - done - - - name: build windows - run: make build_windows - test: name: test runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + go: [ "1.16.10" ] steps: - - name: Check out code into the Go module directory uses: actions/checkout@v2 - name: Set up Go 1.x - uses: actions/setup-go@v2 + uses: WillAbides/setup-go-faster@v1.7.0 with: - go-version: ${{ env.GO_VERSION }} + go-version: ${{ matrix.go }} - run: go version - - name: go mod vendor - run: go mod vendor + - name: build all + run: make build_all - - name: test linux + - name: run tests run: make test_linux diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 721b5e3..2a47dd8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,39 +1,237 @@ on: + # You must provide a tag either via the action input or the git ref (i.e push / create a tag). + # If you do not provide a tag the action will fail. + + # If the tag of the release you are creating does not yet exist, you should set + # both the tag and commit action inputs. commit can point to a commit hash or a branch name (ex - main). +# workflow_dispatch: +# inputs: +# branch: +# description: 'Define branch name to run the release GH action against' +# required: true +# default: 'main' release: - types: [published] + type: [created] + push: + tags: + - v1.* + branches: + - main env: - GO_VERSION: "1.15.15" + GO_VERSION: "1.16.10" LINUX_ARCHES: "amd64 386 arm arm64 s390x mips64le ppc64le" - REPOSITORY: flannelcni/flannel-cni-plugin + REPOSITORY: flannelcni/flannel-cni-plugin jobs: - build-and-push-images: + setup-go: runs-on: ubuntu-latest permissions: contents: read packages: write + strategy: + fail-fast: false + matrix: + go: [ "1.16.10" ] + outputs: + GOPATH: ${{ steps.setup-go.outputs.GOPATH }} + GOROOT: ${{ steps.setup-go.outputs.GOROOT }} + GOCACHE: ${{ steps.setup-go.outputs.GOCACHE }} + GOMODCACHE: ${{ steps.setup-go.outputs.GOMODCACHE }} + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 1 + - uses: WillAbides/setup-go-faster@v1.7.0 + id: setup-go + with: + go-version: ${{ matrix.go }} + - name: go mod vendor and tidy + run: make vendor + - uses: actions/cache@v2 + id: cache-go + with: + path: | + {{ outputs.GOPATH }} + {{ outputs.GOMODCACHE }} + {{ outputs.GOCACHE }} + {{ outputs.GOROOT }} + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + build: + needs: setup-go + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + go: [ "1.16.10" ] + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 1 + + - uses: WillAbides/setup-go-faster@v1.7.0 + id: setup-go + if: steps.cache-go.outputs.cache-hit != 'true' + with: + go-version: ${{ matrix.go }} + + - name: go mod vendor and tidy + if: steps.cache-go.outputs.cache-hit != 'true' + run: make vendor + + - name: build all binaries for release + if: steps.cache-binaries.outputs.cache-hit != 'true' + run: make build_all + + # - uses: dominikh/staticcheck-action@v1.0.0 + # with: + # version: "2021.1.2" + # install-go: false + # cache-key: ${{ matrix.go }} + + - name: Cache build binaries + id: cache-binaries + uses: actions/cache@v2 + env: + cache-name: binaries + with: + path: ${{ needs.setup-go.outputs.GOPATH }}/src/github.com/flannel-io/cni-plugin/dist + key: ${{ runner.os }}-binaries-${{ env.cache-name }}-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-binaries-${{ env.cache-name }} + ${{ runner.os }}-binaries- + ${{ runner.os }}- + + + test: + needs: [setup-go, build] + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + go: [ "1.16.10" ] + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 1 + - uses: WillAbides/setup-go-faster@v1.7.0 + if: steps.cache-go.outputs.cache-hit != 'true' + id: setup-go + with: + go-version: ${{ matrix.go }} + + - name: run tests + run: make test_linux + - name: run go vet + run: go vet + + package: + needs: [setup-go, build, test] + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + strategy: + fail-fast: false + matrix: + go: [ "1.16.10" ] + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 1 + - uses: WillAbides/setup-go-faster@v1.7.0 + id: setup-go + if: steps.cache-go.outputs.cache-hit != 'true' + with: + go-version: ${{ matrix.go }} + + - name: create packages for release + run: make release + + - name: Cache build tarfiles + id: cache-tarfiles + uses: actions/cache@v2 + env: + cache-name: tarfiles + with: + path: ${{ needs.setup-go.outputs.GOPATH }}/src/github.com/flannel-io/cni-plugin/release-${{ github.ref_name }} + key: ${{ runner.os }}-tarfiles-${{ env.cache-name }}-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-tarfiles-${{ env.cache-name }} + ${{ runner.os }}-tarfiles- + ${{ runner.os }}- + + - uses: actions/upload-artifact@v2 + id: upload-tarfiles + with: + name: flannel-cni-plugin-tarfiles + path: ${{ needs.setup-go.outputs.GOPATH }}/src/github.com/flannel-io/cni-plugin/release-${{ github.ref_name }}/ + + - uses: actions/upload-artifact@v2 + id: upload-binaries + with: + name: flannel-cni-plugin-binaries + path: ${{ needs.setup-go.outputs.GOPATH }}/src/github.com/flannel-io/cni-plugin/dist/ + + release: + needs: [setup-go, build, test, package] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 1 + - uses: actions/download-artifact@v2 + with: + id: download-tarfiles + name: flannel-cni-plugin-tarfiles + path: ~/release/ + - uses: actions/download-artifact@v2 + id: download-binaries + with: + name: flannel-cni-plugin-binaries + path: ~/release/ + - uses: ncipollo/release-action@v1 + id: release-artifacts + with: + artifacts: "~/release/*" +# prerelease: true + generateReleaseNotes: true + allowUpdates: true + commit: ${{ github.sha }} + tag: ${{ github.ref_name }} + omitBodyDuringUpdate: true + omitNameDuringUpdate: true + omitPrereleaseDuringUpdate: true + # bodyFile: "body.md" + # token: ${{ secrets.GITHUB_TOKEN }} + + build-and-push-images: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + strategy: + fail-fast: false + matrix: + go: [ "1.16.10" ] steps: - name: Checkout repository uses: actions/checkout@v2 - - name: Set up Go 1.x - uses: actions/setup-go@v2 + - uses: WillAbides/setup-go-faster@v1.7.0 + id: setup-go with: - go-version: ${{ env.GO_VERSION }} + go-version: ${{ matrix.go }} - name: go mod vendor run: go mod vendor - name: build linux - run: | - set -e - for arch in ${LINUX_ARCHES}; do - echo "Building for arch $arch" - ARCH=$arch make build_linux - file dist/flannel-$arch - done + run: make build_all_linux_for_images - name: Set up QEMU uses: docker/setup-qemu-action@v1 @@ -45,86 +243,46 @@ jobs: id: meta uses: docker/metadata-action@v3 with: - images: ${{ env.REPOSITORY }} - flavor: latest=false - tags: | - type=ref,event=tag + go-version: ${{ matrix.go }} - - name: Log in to Docker Hub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - - name: Build and push Docker image for amd64 - if: github.repository_owner == 'flannel-io' - uses: docker/build-push-action@v2 - with: - context: . - file: Dockerfile.amd64 - push: true - tags: ${{ steps.meta.outputs.tags }}-amd64 + - name: go mod vendor and tidy + run: make vendor - - name: Build and push Docker image for arm - if: github.repository_owner == 'flannel-io' - uses: docker/build-push-action@v2 - with: - context: . - file: Dockerfile.arm - push: true - tags: ${{ steps.meta.outputs.tags }}-arm + - name: build all + run: make build_all - - name: Build and push Docker image for arm64 - if: github.repository_owner == 'flannel-io' - uses: docker/build-push-action@v2 - with: - context: . - file: Dockerfile.arm64 - push: true - tags: ${{ steps.meta.outputs.tags }}-arm64 + - name: run tests + run: make test_linux - - name: Build and push Docker image for s390x - if: github.repository_owner == 'flannel-io' - uses: docker/build-push-action@v2 - with: - context: . - file: Dockerfile.s390x - push: true - tags: ${{ steps.meta.outputs.tags }}-s390x + - name: run go vet + run: go vet - - name: Build and push Docker image for ppc64le - if: github.repository_owner == 'flannel-io' - uses: docker/build-push-action@v2 + - uses: dominikh/staticcheck-action@v1.0.0 with: - context: . - file: Dockerfile.ppc64le - push: true - tags: ${{ steps.meta.outputs.tags }}-ppc64le + version: "2021.1.2" + install-go: false + cache-key: ${{ matrix.go }} - build-and-push-multi-arch-image: - needs: [build-and-push-images] + upload-binaries: runs-on: ubuntu-latest - + strategy: + fail-fast: false + matrix: + go: [ "1.16.10" ] steps: - name: Checkout repository uses: actions/checkout@v2 - - name: Set up Go 1.x - uses: actions/setup-go@v2 + - uses: WillAbides/setup-go-faster@v1.7.0 + id: setup-go with: - go-version: ${{ env.GO_VERSION }} + go-version: ${{ matrix.go }} - name: go mod vendor run: go mod vendor - name: build linux - run: | - set -e - for arch in ${LINUX_ARCHES}; do - echo "Building for arch $arch" - ARCH=$arch make build_linux - file dist/flannel-$arch - done + run: make build_all_linux_for_images - name: Set up QEMU uses: docker/setup-qemu-action@v1 @@ -154,12 +312,14 @@ jobs: docker pull ${{ steps.meta.outputs.tags }}-amd64 docker pull ${{ steps.meta.outputs.tags }}-arm64 docker pull ${{ steps.meta.outputs.tags }}-arm + docker pull ${{ steps.meta.outputs.tags }}-mips64le docker pull ${{ steps.meta.outputs.tags }}-ppc64le docker pull ${{ steps.meta.outputs.tags }}-s390x docker manifest create ${{ steps.meta.outputs.tags }} ${{ steps.meta.outputs.tags }}-amd64 ${{ steps.meta.outputs.tags }}-arm64 ${{ steps.meta.outputs.tags }}-arm ${{ steps.meta.outputs.tags }}-ppc64le ${{ steps.meta.outputs.tags }}-s390x docker manifest annotate ${{ steps.meta.outputs.tags }} ${{ steps.meta.outputs.tags }}-amd64 --arch amd64 docker manifest annotate ${{ steps.meta.outputs.tags }} ${{ steps.meta.outputs.tags }}-arm64 --arch arm64 docker manifest annotate ${{ steps.meta.outputs.tags }} ${{ steps.meta.outputs.tags }}-arm --arch arm + docker manifest annotate ${{ steps.meta.outputs.tags }} ${{ steps.meta.outputs.tags }}-mips64le --arch mips64le docker manifest annotate ${{ steps.meta.outputs.tags }} ${{ steps.meta.outputs.tags }}-ppc64le --arch ppc64le docker manifest annotate ${{ steps.meta.outputs.tags }} ${{ steps.meta.outputs.tags }}-s390x --arch s390x docker manifest push ${{ steps.meta.outputs.tags }} diff --git a/.gitignore b/.gitignore index d484c87..1e76b47 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ /bin /vendor +/dist +.idea* +static-check.log diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..95b1300 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,78 @@ +ARG GOLANG_VERSION +FROM library/golang:${GOLANG_VERSION}-alpine AS build +ARG TAG +RUN set -x \ + && apk --no-cache add \ + bash \ + curl \ + git \ + tar +COPY ./scripts/semver-parse.sh /semver-parse.sh +RUN chmod +x /semver-parse.sh +RUN curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s v1.43.0 +RUN git clone -b $(/semver-parse.sh ${TAG} all) --depth=1 https://github.com/flannel-io/cni-plugin ${GOPATH}/src/github.com/flannel-io/cni-plugin +WORKDIR ${GOPATH}/src/github.com/flannel-io/cni-plugin + + +FROM build AS flannel-cni +ARG TAG + +WORKDIR ${GOPATH}/src/github.com/flannel-io/cni-plugin + +RUN \ + set -ex; \ + source ./scripts/version.sh; \ + chmod +x ./scripts/* + +ENV SRC_DIR=${SRC_DIR:-${pwd}} +ENV DOCKER=${DOCKER:-docker} +ENV GO=${GO:-go} +ENV GOPATH=${GOPATH:-'${go env GOPATH}'} +ENV RELEASE_DIR=${GOPATH}/src/github.com/flannel-io/cni-plugin/release-${TAG} +ENV OUTPUT_DIR=${GOPATH}/src/github.com/flannel-io/cni-plugin/dist + +# Always clean first +RUN \ + rm -rf ${OUTPUT_DIR} \ + && rm -rf ${RELEASE_DIR} \ + && mkdir -p ${RELEASE_DIR} \ + && mkdir -p ${OUTPUT_DIR} + +RUN go mod vendor && go mod tidy + +# for ARCH IN ${ALL_ARCH}; do +RUN \ + for arch in amd64 386 arm arm64 s390x mips64le ppc64le; do \ + GOARCH=${arch} ./scripts/build_flannel.sh; \ + for format in tgz; do \ + FILENAME=cni-plugin-flannel-linux-${arch}-${TAG}.${format}; \ + FILEPATH=${RELEASE_DIR}/${FILENAME}; \ + tar -C ${OUTPUT_DIR} --owner=0 --group=0 -caf ${FILEPATH} . ; \ + done; \ + done + +RUN \ + GOOS=windows GOARCH=amd64 ./scripts/build_flannel.sh; \ + for format in tgz; do \ + FILENAME=cni-plugin-flannel-windows-${GOARCH}-${TAG}.${format}; \ + FILEPATH=${RELEASE_DIR}/${FILENAME}; \ + tar -C ${OUTPUT_DIR} --owner=0 --group=0 -caf ${FILEPATH} . ; \ + done + +RUN \ + for arch in amd64 386 arm arm64 s390x mips64le ppc64le; do \ + GOARCH=${arch} ./scripts/check_static.sh >> static-check.log; \ + done + + +WORKDIR ${RELEASE_DIR} +RUN \ + for f in *.tgz; do sha1sum ${f} > ./${f}.sha1; done; \ + for f in *.tgz; do sha256sum ${f} > ./${f}.sha256; done; \ + for f in *.tgz; do sha512sum ${f} > ./${f}.sha512; done; + +FROM build AS flannel-cni-collect +ARG TAG +COPY --from=flannel-cni ${GOPATH}/src/github.com/flannel-io/cni-plugin/dist/ /go/src/github.com/flannel-io/cni-plugin/dist/ +COPY --from=flannel-cni ${GOPATH}/src/github.com/flannel-io/cni-plugin/release-${TAG}/ /go/src/github.com/flannel-io/cni-plugin/release-${TAG}/ +COPY --from=flannel-cni ${GOPATH}/src/github.com/flannel-io/cni-plugin/static-check.log /go/src/github.com/flannel-io/cni-plugin/static-check.log diff --git a/Makefile b/Makefile index d8c9ed4..87f7fad 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,18 @@ -.PHONY: build_linux build_windows test_linux -.PHONY: clean release +.PHONY: vendor build_linux build_windows build_all build_all_docker +.PHONY: clean vendor release -REGISTRY?=rancher/flannel-cni-plugin -QEMU_VERSION=v3.0.0 +REGISTRY?=docker.io/flannelcni/flannel-cni-plugin # Default tag and architecture. Can be overridden TAG?=$(shell git describe --tags --dirty --always) ARCH?=amd64 +SRC_DIR?=$(pwd) +GO?=$(go) +GOPATH?=$(go env GOPATH) + +# this is the upstream CNI plugin version used for testing +TEST_TAG?=v1.0.0 + # Only enable CGO (and build the UDP backend) on AMD64 ifeq ($(ARCH),amd64) CGO_ENABLED=1 @@ -14,83 +20,66 @@ else CGO_ENABLED=0 endif -# Go version to use for builds -GO_VERSION=1.15.5 +# Go version to use for builds. Can be overridden +GOLANG_VERSION?=1.16.10 -release: dist/qemu-s390x-static dist/qemu-ppc64le-static dist/qemu-aarch64-static dist/qemu-arm-static - ARCH=amd64 make dist/flannel-$(TAG)-amd64.docker - ARCH=arm make dist/flannel-$(TAG)-arm.docker - ARCH=arm64 make dist/flannel-$(TAG)-arm64.docker - ARCH=ppc64le make dist/flannel-$(TAG)-ppc64le.docker - ARCH=s390x make dist/flannel-$(TAG)-s390x.docker - @echo "Everything should be built for $(TAG)" - @echo "Add all flannel-* and *.tar.gz files from dist/ to the Github release" - @echo "Use make docker-push-all to push the images to a registry" +build_all: vendor build_all_linux build_windows + @echo "All arches should be built for $(TAG)" + +build_all_linux: vendor + GOOS=linux GOARCH=amd64 scripts/build_flannel.sh + GOOS=linux GOARCH=386 scripts/build_flannel.sh + GOOS=linux GOARCH=arm scripts/build_flannel.sh + GOOS=linux GOARCH=arm64 scripts/build_flannel.sh + GOOS=linux GOARCH=s390x scripts/build_flannel.sh + GOOS=linux GOARCH=mips64le scripts/build_flannel.sh + GOOS=linux GOARCH=ppc64le scripts/build_flannel.sh + + +build_all_linux_for_images: vendor + GOOS=linux GOARCH=amd64 scripts/build_flannel_for_images.sh + GOOS=linux GOARCH=386 scripts/build_flannel_for_images.sh + GOOS=linux GOARCH=arm scripts/build_flannel_for_images.sh + GOOS=linux GOARCH=arm64 scripts/build_flannel_for_images.sh + GOOS=linux GOARCH=s390x scripts/build_flannel_for_images.sh + GOOS=linux GOARCH=mips64le scripts/build_flannel_for_images.sh + GOOS=linux GOARCH=ppc64le scripts/build_flannel_for_images.sh -dist/flannel-$(TAG)-$(ARCH).docker: dist/flannel-$(ARCH) - docker build -f Dockerfile.$(ARCH) -t $(REGISTRY):$(TAG)-$(ARCH) . -# docker save -o dist/flannel-$(TAG)-$(ARCH).docker $(REGISTRY):$(TAG)-$(ARCH) vendor: go mod tidy go mod vendor + +build_all_docker: vendor + docker build \ + --no-cache \ + --build-arg GOLANG_VERSION=$(GOLANG_VERSION) \ + --build-arg TAG=$(TAG) \ + --tag $(REGISTRY):$(TAG) \ + --tag $(REGISTRY):$(TAG)-$(ARCH) \ + -f Dockerfile \ + . + build_linux: vendor GOOS=linux GOARCH=$(ARCH) scripts/build_flannel.sh build_windows: vendor - GOOS=windows scripts/build_flannel.sh - -# This will build flannel cni-plugin natively using golang image -dist/flannel-$(ARCH): dist/qemu-$(ARCH)-static - # valid values for ARCH are [amd64 arm arm64 ppc64le s390x] - docker run -e CGO_ENABLED=$(CGO_ENABLED) -e GOARCH=$(ARCH) -e GOCACHE=/go -e GOOS=linux -e GOFLAGS="${GOFLAGS} -mod=vendor" \ - -u $(shell id -u):$(shell id -g) \ - -v $(CURDIR)/dist/qemu-$(ARCH)-static:/usr/bin/qemu-$(ARCH)-static \ - -v $(CURDIR):/go/src/github.com/flannel-io/flannel:ro \ - -v $(CURDIR)/bin:/go/src/github.com/flannel-io/flannel/bin \ - -v $(CURDIR)/dist:/go/src/github.com/flannel-io/flannel/dist \ - golang:$(GO_VERSION) /bin/bash -c '\ - cd /go/src/github.com/flannel-io/flannel && \ - go build -o "./bin/flannel" . && \ - mv bin/flannel dist/flannel-$(ARCH)' - -dist/qemu-%-static: - if [ "$(@F)" = "qemu-amd64-static" ]; then \ - wget -O dist/qemu-amd64-static https://github.com/multiarch/qemu-user-static/releases/download/$(QEMU_VERSION)/qemu-x86_64-static; \ - elif [ "$(@F)" = "qemu-arm64-static" ]; then \ - wget -O dist/qemu-arm64-static https://github.com/multiarch/qemu-user-static/releases/download/$(QEMU_VERSION)/qemu-aarch64-static; \ - else \ - wget -O dist/$(@F) https://github.com/multiarch/qemu-user-static/releases/download/$(QEMU_VERSION)/$(@F); \ - fi - -docker-push: dist/flannel-$(TAG)-$(ARCH).docker - docker push $(REGISTRY):$(TAG)-$(ARCH) - -docker-manifest-amend: - DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create --amend $(REGISTRY):$(TAG) $(REGISTRY):$(TAG)-$(ARCH) - -docker-manifest-push: - DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push --purge $(REGISTRY):$(TAG) - -docker-push-all: - ARCH=amd64 make docker-push docker-manifest-amend - ARCH=arm make docker-push docker-manifest-amend - ARCH=arm64 make docker-push docker-manifest-amend - ARCH=ppc64le make docker-push docker-manifest-amend - ARCH=s390x make docker-push docker-manifest-amend - make docker-manifest-push - -test_linux: - scripts/test_linux.sh - -build_image: build_linux - docker build . -f Dockerfile.linux - -push_image: build_image - docker push quay.io/coreos/flannel-cni:${VERSION} + GOOS=windows GOARCH=$(ARCH) scripts/build_flannel.sh + +test_linux: vendor build_linux + TAG=$(TEST_TAG) scripts/test_linux.sh clean: rm -f dist/flannel* - rm -f dist/qemu-* + rm -f release/cni-plugin-flannel* -#release: build_image test_linux push_image +package: vendor + scripts/package.sh + +release: build_all + scripts/package.sh + +release_docker: clean vendor + scripts/release.sh + @echo "Everything should be built for $(TAG)" + @echo "Add all flannel-* and *.tar.gz files from dist/ and release/ to the Github release" \ No newline at end of file diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 0000000..58dd04c --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,49 @@ +# Release process + +## Resulting artifacts + +### [Manual] Release using local artifacts +Creating a new release via `make release` produces the following directories containg artifacts: + +- Binaries: + - `${GOPATH}/src/github.com/flannel-io/cni-plugin/dist`) + - `flannel-` binaries + + +- Tarfiles: + - `${GOPATH}/src/github.com/flannel-io/cni-plugin/release-"${TAG}"` + - `cni-plugin-flannel---.tar.gz` tarfiles containing one binary + - `.sha1`, `.sha256`, and `.sha512` files for each tarfile. + +### [Manual] Release using Docker artifacts +Creating a new release via `make release_docker` produces the following artifacts: + +- Binaries (stored in the `release-` directory) : + - `flannel--.tgz` binaries + - `flannel-.tgz` binary (copy of amd64 platform binary) + - `.sha1`, `.sha256`, and `.sha512` files for the above files. + +## Preparing for a release +1. Releases are performed by maintainers and should usually be discussed and planned at a maintainer meeting. + - Choose the version number. It should be prefixed with `v`, e.g. `v1.2.3` + - Take a quick scan through the PRs and issues to make sure there isn't anything crucial that _must_ be in the next release. + - Create a draft of the release note + - Discuss the level of testing that's needed and create a test plan if sensible + - Check what version of `go` is used in the build container, updating it if there's a new stable release. + - Update the vendor directory and Godeps to pin to the corresponding containernetworking/cni release. Create a PR, makes sure it passes CI and get it merged. + +## Creating the release artifacts +1. Make sure you are on the master branch and don't have any local uncommitted changes. +2. Create a signed tag for the release `git tag -s $VERSION` (Ensure that GPG keys are created and added to GitHub) +3. Run the release script from the root of the repository + - `scripts/release.sh` + - The script requires Docker and ensures that a consistent environment is used. + - The artifacts will now be present in the `release-` directory. +4. Test these binaries according to the test plan. + +## Publishing the release +1. Push the tag to git `git push origin ` +2. Create a release on Github, using the tag which was just pushed. +3. Attach all the artifacts from the release directory. +4. Add the release note to the release. + diff --git a/flannel.go b/flannel.go index e7d45e6..fb60e36 100644 --- a/flannel.go +++ b/flannel.go @@ -27,18 +27,14 @@ import ( "net" "os" "path/filepath" + "runtime" "strconv" "strings" "github.com/containernetworking/cni/pkg/invoke" "github.com/containernetworking/cni/pkg/skel" "github.com/containernetworking/cni/pkg/types" - "github.com/containernetworking/cni/pkg/version" -) - -var ( - Version = "v1.0.0" - StringVersion = fmt.Sprintf("Flannel binary %s", Version) + cni "github.com/containernetworking/cni/pkg/version" ) const ( @@ -46,6 +42,13 @@ const ( defaultDataDir = "/var/lib/cni/flannel" ) +var ( + Program string + Version string + Commit string + buildDate string +) + type NetConf struct { types.NetConf @@ -272,7 +275,8 @@ func cmdDel(args *skel.CmdArgs) error { } func main() { - skel.PluginMain(cmdAdd, cmdCheck, cmdDel, version.All, StringVersion) + fullVer := fmt.Sprintf("CNI Plugin %s version %s (%s/%s) commit %s built on %s", Program, Version, runtime.GOOS, runtime.GOARCH, Commit, buildDate) + skel.PluginMain(cmdAdd, cmdCheck, cmdDel, cni.All, fullVer) } func cmdCheck(args *skel.CmdArgs) error { diff --git a/pkg/version/version.go b/pkg/version/version.go deleted file mode 100644 index 87175b5..0000000 --- a/pkg/version/version.go +++ /dev/null @@ -1,12 +0,0 @@ -package version - -import ( - "strings" -) - -var ( - Program = "flannel" - ProgramUpper = strings.ToUpper(Program) - Version = "dev" - GitCommit = "HEAD" -) diff --git a/scripts/build_flannel.sh b/scripts/build_flannel.sh index 4f1dc45..2253da0 100755 --- a/scripts/build_flannel.sh +++ b/scripts/build_flannel.sh @@ -1,29 +1,61 @@ #!/usr/bin/env bash -set -e -cd $(dirname "$0")/.. - -if [ -z "$VERSION" ]; then - set +e - git describe --tags --abbrev=0 > /dev/null 2>&1 - if [ "$?" != "0" ]; then - VERSION="master" - else - VERSION=$(git describe --tags --abbrev=0) - fi - set -e +set -ex + +cd $(dirname $0)/.. + +source ./scripts/version.sh + +if [ -z "${GODEBUG}" ]; then + EXTRA_LDFLAGS="${EXTRA_LDFLAGS} -w" + DEBUG_GO_GCFLAGS="" + DEBUG_TAGS="" +else + DEBUG_GO_GCFLAGS='-gcflags=all=-N -l' fi -export GOOS="${GOOS:-linux}" -export GOARCH="${GOARCH:-amd64}" -export GOFLAGS="${GOFLAGS} -mod=vendor" -export GLDFLAGS+="-X main.Version=${VERSION:-master}" +BUILDTAGS="netgo osusergo no_stage static_build" +GO_BUILDTAGS="${GO_BUILDTAGS} ${BUILDTAGS} ${DEBUG_TAGS}" +PKG="github.com/flannel-io/cni-plugin" +VENDOR_PREFIX="${PKG}/vendor/" -mkdir -p "${PWD}/dist" +VERSION_FLAGS=" + -X main.Version=${VERSION} + -X main.Commit=${COMMIT:0:8} + -X main.Program=${PROG:-flannel} + -X main.buildDate=${BUILD_DATE} +" +# STATIC_FLAGS='-linkmode external -extldflags "-static"' +#STATIC_FLAGS='-extldflags "-static -Wl,--fatal-warnings"' +# shellcheck disable=SC2089 +STATIC_FLAGS='-extldflags "-static"' -echo "Building flannel for ${GOOS} in ${GOARCH}" +GO_LDFLAGS="${STATIC_FLAGS} ${EXTRA_LDFLAGS}" -if [ "$GOOS" == "linux" ]; then - go build ${GOFLAGS} -ldflags "${GLDFLAGS}" -o "${PWD}/dist/flannel-${GOARCH}" "$@" . +if [ -z "${CGO_ENABLED}" ]; then + CGO_ENABLED="${CGO_ENABLED}" else - go build ${GOFLAGS} -ldflags "${GLDFLAGS}" -o "${PWD}/dist/flannel.exe" "$@" . + CGO_ENABLED=0 +fi + +echo "Building flannel for ${GOOS} in ${GOARCH}" +echo "${DEBUG_GO_GCFLAGS}" + +if [ "${GOOS}" = "linux" ]; then + go build \ + -tags "${GO_BUILDTAGS}" \ + ${GO_GCFLAGS} ${GO_BUILD_FLAGS} \ + -o ${OUTPUT_DIR}/${PROG}-${GOARCH} \ + -ldflags "${GO_LDFLAGS} ${VERSION_FLAGS}" \ + ${GO_TAGS} +elif [ "${GOOS}" = "windows" ]; then + go build \ + -tags "${GO_BUILDTAGS}" \ + ${GO_GCFLAGS} ${GO_BUILD_FLAGS} \ + -o ${OUTPUT_DIR}/${PROG}-${GOARCH}.exe \ + -ldflags "${VERSION_FLAGS} ${GO_LDFLAGS}" +else + echo "GOOS:${GOOS} is not yet supported" + echo "Please file a new GitHub issue requesting support for GOOS:${GOOS}" + echo "https://github.com/flannel-io/cni-plugin/issues" + exit 1 fi diff --git a/scripts/build_flannel_for_images.sh b/scripts/build_flannel_for_images.sh new file mode 100755 index 0000000..ced90bb --- /dev/null +++ b/scripts/build_flannel_for_images.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +set -ex + +cd $(dirname $0)/.. + +source ./scripts/version.sh + +if [ -z "${GODEBUG}" ]; then + EXTRA_LDFLAGS="${EXTRA_LDFLAGS} -w" + DEBUG_GO_GCFLAGS="" + DEBUG_TAGS="" +else + DEBUG_GO_GCFLAGS='-gcflags=all=-N -l' +fi + +BUILDTAGS="netgo osusergo no_stage static_build" +GO_BUILDTAGS="${GO_BUILDTAGS} ${BUILDTAGS} ${DEBUG_TAGS}" +PKG="github.com/flannel-io/cni-plugin" +VENDOR_PREFIX="${PKG}/vendor/" + +VERSION_FLAGS=" + -X main.Version=${VERSION} + -X main.Commit=${COMMIT:0:8} + -X main.Program=${PROG:-flannel} + -X main.buildDate=${BUILD_DATE} +" +# STATIC_FLAGS='-linkmode external -extldflags "-static"' +#STATIC_FLAGS='-extldflags "-static -Wl,--fatal-warnings"' +# shellcheck disable=SC2089 +STATIC_FLAGS='-extldflags "-static"' + +GO_LDFLAGS="${STATIC_FLAGS} ${EXTRA_LDFLAGS}" + +mkdir -p "${PWD}/dist" + +if [ -z ${CGO_ENABLED} ]; then + CGO_ENABLED=${CGO_ENABLED} +else + CGO_ENABLED=0 +fi + +echo "Building flannel for ${GOOS} in ${GOARCH}" +echo "${DEBUG_GO_GCFLAGS}" + +if [ "${GOOS}" = "linux" ]; then + go build \ + -tags "${GO_BUILDTAGS}" \ + ${GO_GCFLAGS} ${GO_BUILD_FLAGS} \ + -o "${PWD}/dist/${PROG}-${GOARCH}" \ + -ldflags "${GO_LDFLAGS} ${VERSION_FLAGS}" \ + ${GO_TAGS} +elif [ "${GOOS}" = "windows" ]; then + go build \ + -tags "${GO_BUILDTAGS}" \ + ${GO_GCFLAGS} ${GO_BUILD_FLAGS} \ + -o "${PWD}/dist/${PROG}-${GOARCH}.exe" \ + -ldflags "${VERSION_FLAGS} ${GO_LDFLAGS}" +else + echo "GOOS:${GOOS} is not yet supported" + echo "Please file a new GitHub issue requesting support for GOOS:${GOOS}" + echo "https://github.com/flannel-io/cni-plugin/issues" + exit 1 +fi diff --git a/scripts/check_static.sh b/scripts/check_static.sh new file mode 100755 index 0000000..a0a3f24 --- /dev/null +++ b/scripts/check_static.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -ex + +cd $(dirname $0)/.. +source ./scripts/version.sh + +# assert that the linux flannel cni-plugin binary is fully statically linked + +if [[ ${GOOS} == "linux" ]] && type -a scripts/go-assert-static.sh >/dev/null 2>&1; then + if GOOS=${GOOS} scripts/go-assert-static.sh ${OUTPUT_DIR}/flannel-${GOARCH}; then + printf 'verified static links for flannel-%s\n' "${GOARCH}" + else + echo "failed to verify static links for dist/flannel-${GOARCH}" + fi +fi + +# assert that the windows flannel cni-plugin binary is fully statically linked +if [[ ${GOOS} == "windows" ]] && type -a scripts/go-assert-static.sh >/dev/null 2>&1; then + if GOOS=${GOOS} scripts/go-assert-static.sh ${OUTPUT_DIR}/flannel-${GOARCH}.exe; then + printf 'verified static links for flannel-%s.exe\n' "${GOARCH}" + else + echo "failed to verify static links for dist/flannel-${GOARCH}.exe" + fi +fi diff --git a/scripts/go-assert-static.sh b/scripts/go-assert-static.sh new file mode 100755 index 0000000..8008690 --- /dev/null +++ b/scripts/go-assert-static.sh @@ -0,0 +1,31 @@ +#!/bin/sh +if [ -z "$*" ]; then + echo "usage: $0 file1 [file2 ... fileN]" +fi +for exe in "${@}"; do + if [ ! -x "${exe}" ]; then + echo "$exe: file not found" >&2 + exit 1 + fi + + case $GOOS in + linux) + if ! file "${exe}" | grep -E '.*ELF.*executable, .*, statically linked,.*'; then + file "${exe}" >&2 + echo "${exe}: not a statically linked executable" >&2 + exit 1 + fi + ;; + windows) + if ! ldd "${exe}" 2>&1 | grep -qE '.*not a dynamic executable' && ! objdump -T "${exe}" 2>&1 | tr -d '\n' | grep -E '.*pei-x86-64.*not a dynamic object.*no symbols'; then + file "${exe}" >&2 + echo "${exe}: not a statically linked Windows executable" >&2 + exit 1 + fi + ;; + *) + echo "GOOS:${GOOS} is not yet supported" + exit 1 + ;; + esac +done diff --git a/scripts/package.sh b/scripts/package.sh new file mode 100755 index 0000000..b49dc82 --- /dev/null +++ b/scripts/package.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +set -ex + +cd $(dirname $0)/.. +source ./scripts/version.sh + +mkdir -p "${GOPATH}"/src/github.com/flannel-io/cni-plugin/release-"${TAG}" +mkdir -p "${GOPATH}"/src/github.com/flannel-io/cni-plugin/dist +cd "${GOPATH}"/src/github.com/flannel-io/cni-plugin +umask 0022 + + +for arch in amd64 386 arm arm64 s390x mips64le ppc64le; do + echo $arch + for format in tgz; do + FILENAME=cni-plugin-flannel-linux-$arch-"${TAG}".$format + FILEPATH="${RELEASE_DIR}"/$FILENAME + tar -C "${OUTPUT_DIR}" --owner=0 --group=0 -caf "$FILEPATH" . + done +done + + +for format in tgz; do + FILENAME=cni-plugin-flannel-windows-"${GOARCH}"-"${TAG}".$format + FILEPATH="${RELEASE_DIR}"/$FILENAME + tar -C "${OUTPUT_DIR}" --owner=0 --group=0 -caf "$FILEPATH" . +done + +cd "${SRC_DIR}" +# linux +for arch in amd64 386 arm arm64 s390x mips64le ppc64le; do + GOOS=${GOOS:-$("${GO}" env GOOS)} + RELEASE_DIR=${GOPATH}/src/github.com/flannel-io/cni-plugin/release-"${TAG}" \ + OUTPUT_DIR=${GOPATH}/src/github.com/flannel-io/cni-plugin/dist \ + GOARCH=$arch ./scripts/check_static.sh >> static-check.log +done + +# windows +for arch in amd64; do + unset GOARCH + unset GOOS + echo $arch + RELEASE_DIR=${GOPATH}/src/github.com/flannel-io/cni-plugin/release-"${TAG}" \ + OUTPUT_DIR=${GOPATH}/src/github.com/flannel-io/cni-plugin/dist \ + GOARCH=$arch GOOS=windows ./scripts/check_static.sh >> static-check.log +done + +cd "${RELEASE_DIR}" +for f in *.tgz; do sha1sum $f > $f.sha1; done +for f in *.tgz; do sha256sum $f > $f.sha256; done +for f in *.tgz; do sha512sum $f > $f.sha512; done \ No newline at end of file diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100755 index 0000000..74e2f86 --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +set -ex + +cd "$(dirname "${0}")"/.. +source ./scripts/version.sh + +SRC_DIR=${SRC_DIR:-$PWD} +DOCKER=${DOCKER:-docker} +GO=${GO:-go} +GOPATH=${GOPATH:-$(go env GOPATH)} + +RELEASE_DIR=${GOPATH}/src/github.com/flannel-io/cni-plugin/release-"${TAG}" +OUTPUT_DIR=${GOPATH}/src/github.com/flannel-io/cni-plugin/dist + +# Always clean first +rm -rf "${OUTPUT_DIR}" +rm -rf "${RELEASE_DIR}" +mkdir -p "${RELEASE_DIR}" +mkdir -p "${OUTPUT_DIR}" + + +$DOCKER run -ti -v "${SRC_DIR}":"${GOPATH}"/src/github.com/flannel-io/cni-plugin:z -e TAG="${TAG}" --rm golang:"${GOLANG_VERSION}-alpine" \ +/bin/sh -ex -c "\ + mkdir -p ${GOPATH}/src/github.com/flannel-io/cni-plugin/release-${TAG}; + mkdir -p ${GOPATH}/src/github.com/flannel-io/cni-plugin/dist; + cd ${GOPATH}/src/github.com/flannel-io/cni-plugin; umask 0022; + apk --no-cache add bash tar git; \ + source ./scripts/version.sh; \ + chmod +x ./scripts/* ; + + go mod vendor && go mod tidy + + for arch in amd64 386 arm arm64 s390x mips64le ppc64le; do \ + echo \$arch;\ + GOARCH=\$arch ./scripts/build_flannel.sh; \ + for format in tgz; do \ + FILENAME=cni-plugin-flannel-linux-\$arch-${TAG}.\$format; \ + FILEPATH=${RELEASE_DIR}/\$FILENAME; \ + tar -C ${OUTPUT_DIR} --owner=0 --group=0 -caf \$FILEPATH . ; \ + done; \ + done; + + GOOS=windows GOARCH=amd64 ./scripts/build_flannel.sh; \ + for format in tgz; do \ + FILENAME=cni-plugin-flannel-windows-${GOARCH}-${TAG}.\$format; \ + FILEPATH=${RELEASE_DIR}/\$FILENAME; \ + tar -C ${OUTPUT_DIR} --owner=0 --group=0 -caf \$FILEPATH . ; \ + done; + + for arch in amd64 386 arm arm64 s390x mips64le ppc64le; do \ + GOARCH=\$arch ./scripts/check_static.sh >> static-check.log; \ + done; + + cd ${RELEASE_DIR}; \ + for f in *.tgz; do sha1sum \$f > \$f.sha1; done; \ + for f in *.tgz; do sha256sum \$f > \$f.sha256; done; \ + for f in *.tgz; do sha512sum \$f > \$f.sha512; done; + " diff --git a/scripts/semver-parse.sh b/scripts/semver-parse.sh new file mode 100755 index 0000000..1fe4ce8 --- /dev/null +++ b/scripts/semver-parse.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +set -e + +if [ -z $1 ]; then + echo "error: tag required as argument" + exit 1 +fi + +if [ -z $2 ]; then + echo "error: version required as argument" + exit 1 +fi + +TAG=$1 +VERSION=$2 +MAJOR="" +MINOR="" +PATCH="" + +if [[ "${TAG}" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then + MAJOR=${BASH_REMATCH[1]} + MINOR=${BASH_REMATCH[2]} + PATCH=${BASH_REMATCH[3]} +fi + +if [ "${VERSION}" = "minor" ]; then + echo "${MINOR}" +elif [ "${VERSION}" = "major" ]; then + echo "${MAJOR}" +elif [ "${VERSION}" = "patch" ]; then + echo "${PATCH}" +elif [ "${VERSION}" = "all" ]; then + echo "v${MAJOR}.${MINOR}.${PATCH}" +else + echo "error: unrecognized version" + exit 2 +fi diff --git a/scripts/test_linux.sh b/scripts/test_linux.sh index 23a5d46..ab38685 100755 --- a/scripts/test_linux.sh +++ b/scripts/test_linux.sh @@ -1,19 +1,17 @@ #!/usr/bin/env bash # # Run CNI plugin tests. -# +# # This needs sudo, as we'll be creating net interfaces. # -set -xe +set -ex # switch into the repo root directory cd $(dirname "$0")/.. # What version of the containernetworking/plugins should we use for testing -export CNI_VERSION=${CNI_VERSION:-v1.0.0} - -# Build all plugins before testing -make build_linux +# We now set TEST_TAG in the Makefile and pass it in +CNI_VERSION=${TAG} echo "Running tests" diff --git a/scripts/version.sh b/scripts/version.sh new file mode 100755 index 0000000..fda8e2c --- /dev/null +++ b/scripts/version.sh @@ -0,0 +1,69 @@ +#!/bin/bash +set -ex + +PROG=${PROG:-flannel} +REGISTRY=${REGISTRY:-docker.io/flannelcni/flannel-cni-plugin} +REPO=${REPO:-rancher} +GO=${GO-go} +GOARCH=${GOARCH:-$("${GO}" env GOARCH)} +GOOS=${GOOS:-$("${GO}" env GOOS)} +SRC_DIR=${SRC_DIR:-$PWD} +DOCKER=${DOCKER:-docker} +GOPATH=${GOPATH:-$(go env GOPATH)} + +if [ -z "$GOOS" ]; then + if [ "${OS}" == "Windows_NT" ]; then + GOOS="windows" + else + UNAME_S=$(shell uname -s) + if [ "${UNAME_S}" == "Linux" ]; then + GOOS="linux" + elif [ "${UNAME_S}" == "Darwin" ]; then + GOOS="darwin" + elif [ "${UNAME_S}" == "FreeBSD" ]; then + GOOS="freebsd" + fi + fi +fi + +GIT_TAG=${TAG} +TREE_STATE=clean +BUILD_DATE=$(date -u "+%Y-%m-%dT%H:%M:%SZ") +COMMIT=$(git rev-parse HEAD)$(if ! git diff --no-ext-diff --quiet --exit-code; then echo .dirty; fi) +PLATFORM=${GOOS}-${GOARCH} +RELEASE=${PROG}-${GOARCH} +# hardcode versions unless set specifically +VERSION=${VERSION:-v1.0.0} +GOLANG_VERSION=${GOLANG_VERSION:-1.16.10} + +if [ -d .git ]; then + if [ -z "${GIT_TAG}" ]; then + GIT_TAG=$(git tag -l --contains HEAD | head -n 1) + fi + if [ -n "$(git status --porcelain --untracked-files=no)" ]; then + DIRTY="-dirty" + TREE_STATE=dirty + fi + + COMMIT=$(git log -n3 --pretty=format:"%H %ae" | cut -f1 -d\ | head -1) + if [ -z "${COMMIT}" ]; then + COMMIT=$(git rev-parse HEAD || true) + fi +fi + +if [[ -n "${GIT_TAG}" ]]; then + VERSION=${GIT_TAG} +else + VERSION="${VERSION}-dev+${COMMIT:0:8}$DIRTY" +fi + +if [ -z "${TAG}" ]; then + TAG=${VERSION} +fi + +RELEASE_DIR=${GOPATH}/src/github.com/flannel-io/cni-plugin/release-"${TAG}" +OUTPUT_DIR=${GOPATH}/src/github.com/flannel-io/cni-plugin/dist + +echo "Version: ${VERSION}" +echo "Commit: ${COMMIT}" +