From cb728707d3370ee4c2c295c3fec91a06ebd6d591 Mon Sep 17 00:00:00 2001 From: Lucas Roesler Date: Sun, 29 Aug 2021 10:12:52 +0200 Subject: [PATCH] feat: check server capabilities usin the preferred resources endpoint Using the preferred resources endpoit allows us to test for specific API groups that contain a specific resource kind, in this case we can test for which API groups that exist and support Ingress. ci: remove git from the docker build context Pass the versio data via build arguments instead of passing the entire git database. This cuts the build context in half. ci: update multi-arch build flow Use the build process from faas-netes to simplify the multi-arch build process. ci: allow pushing to fork ghcr repos ci: push preview images for PRs ci: build multi-arch in paraller for speed Signed-off-by: Lucas Roesler --- .dockerignore | 7 +++ .github/workflows/build.yaml | 56 +++++++++++++++++++----- .github/workflows/publish.yaml | 30 ++++++------- .gitignore | 1 + Dockerfile | 9 ++-- Makefile | 78 ++++++++++++++++++++++++++-------- main.go | 43 ++++++++++++++++++- 7 files changed, 175 insertions(+), 49 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..1bdfd1a4 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,7 @@ +.git +.github +.vscode +.tools +artifacts +examples +hack \ No newline at end of file diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 055c254b..952a6c33 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -8,31 +8,62 @@ on: jobs: build: - strategy: - matrix: - go-version: [1.13.x] - os: [ubuntu-latest] - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest steps: - uses: actions/checkout@master - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: ${{ matrix.go-version }} - name: Set up QEMU uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 + - name: Set Username/Repo and ImagePrefix as ENV vars + run: | + echo "USER_REPO=${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV} && \ + echo "IMAGE_PREFIX=ghcr.io/${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV} + - name: Build x86_64 container into library uses: docker/build-push-action@v2 with: context: . file: ./Dockerfile outputs: "type=docker,push=false" + build-args: | + VERSION=latest-dev + GIT_COMMIT=${{ github.sha }} platforms: linux/amd64 tags: | - ghcr.io/openfaas/ingress-operator:${{ github.sha }} + ${{ env.IMAGE_PREFIX }}:${{ github.sha }} + + - name: Login to Docker Registry + uses: docker/login-action@v1 + if: ${{ github.event_name == 'pull_request' }} + with: + registry: ghcr.io + username: ${{ env.USER_REPO }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Publish Pull Request test image + uses: contiamo/retag-push@main + if: ${{ github.event_name == 'pull_request' }} + with: + source: ${{ env.IMAGE_PREFIX }}:${{ github.sha }} + target: | + ${{ env.IMAGE_PREFIX }}:pr-${{github.event.number}} + + build-multi-arch: + # run in parallel to build because multi-arch is slow + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Set Username/Repo and ImagePrefix as ENV vars + run: | + echo "USER_REPO=${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV} && \ + echo "IMAGE_PREFIX=ghcr.io/${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV} - name: Build multi-arch containers for validation only uses: docker/build-push-action@v2 @@ -40,6 +71,9 @@ jobs: context: . file: ./Dockerfile outputs: "type=image,push=false" + build-args: | + VERSION=latest-dev + GIT_COMMIT=${{ github.sha }} platforms: linux/amd64,linux/arm/v7,linux/arm64 tags: | - ghcr.io/openfaas/ingress-operator:${{ github.sha }} + ${{ env.IMAGE_PREFIX }}:${{ github.sha }} diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 20e1efcd..88d2bf87 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -7,17 +7,9 @@ on: jobs: publish: - strategy: - matrix: - go-version: [1.13.x] - os: [ubuntu-latest] - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest steps: - uses: actions/checkout@master - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: ${{ matrix.go-version }} - name: Set up QEMU uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx @@ -25,22 +17,28 @@ jobs: - name: Get TAG id: get_tag run: echo ::set-output name=TAG::${GITHUB_REF#refs/tags/} - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + - name: Set Username/Repo and ImagePrefix as ENV vars + run: | + echo "USER_REPO=${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV} && \ + echo "IMAGE_PREFIX=ghcr.io/${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV} + - name: Login to Docker Registry uses: docker/login-action@v1 with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} registry: ghcr.io + username: ${{ env.USER_REPO }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Push containers uses: docker/build-push-action@v2 with: context: . file: ./Dockerfile outputs: "type=registry,push=true" + build-args: | + VERSION=${{ steps.get_tag.outputs.TAG }} + GIT_COMMIT=${{ github.sha }} platforms: linux/amd64,linux/arm/v7,linux/arm64 tags: | - ghcr.io/openfaas/ingress-operator:${{ github.sha }} - ghcr.io/openfaas/ingress-operator:${{ steps.get_tag.outputs.TAG }} - ghcr.io/openfaas/ingress-operator:latest + ${{ env.IMAGE_PREFIX }}:${{ github.sha }} + ${{ env.IMAGE_PREFIX }}:${{ steps.get_tag.outputs.TAG }} + ${{ env.IMAGE_PREFIX }}:latest diff --git a/.gitignore b/.gitignore index 632ed16c..8b18a53c 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ ingress-operator config password.txt faas-netes/** +test.yaml \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 733a7ef6..ae66829c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,9 +6,14 @@ ARG BUILDPLATFORM ARG TARGETOS ARG TARGETARCH +ARG GIT_COMMIT +ARG VERSION + ENV CGO_ENABLED=0 ENV GO111MODULE=on ENV GOFLAGS=-mod=vendor +ENV GOOS=${TARGETOS} +ENV GOARCH=${TARGETARCH} COPY --from=license-check /license-check /usr/bin/ @@ -22,9 +27,7 @@ ARG OPTS RUN gofmt -l -d $(find . -type f -name '*.go' -not -path "./vendor/*") RUN go test -mod=vendor -v ./... -RUN VERSION=$(git describe --all --exact-match `git rev-parse HEAD` | grep tags | sed 's/tags\///') && \ - GIT_COMMIT=$(git rev-list -1 HEAD) && \ - env ${OPTS} GOOS=${TARGETOS} GOARCH=${TARGETARCH} CGO_ENABLED=${CGO_ENABLED} GOOS=linux go build -mod=vendor -ldflags "-s -w \ +RUN go build -mod=vendor -ldflags "-s -w \ -X github.com/openfaas-incubator/ingress-operator/pkg/version.Release=${VERSION} \ -X github.com/openfaas-incubator/ingress-operator/pkg/version.SHA=${GIT_COMMIT}" \ -a -installsuffix cgo -o ingress-operator . && \ diff --git a/Makefile b/Makefile index a9910a3b..bd417219 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,12 @@ -.PHONY: build push manifest test verify-codegen charts TAG?=latest +.GIT_COMMIT=$(shell git rev-parse HEAD) +.GIT_VERSION=$(shell git describe --tags 2>/dev/null || echo "$(.GIT_COMMIT)") +.GIT_UNTRACKEDCHANGES := $(shell git status --porcelain --untracked-files=no) +ifneq ($(.GIT_UNTRACKEDCHANGES),) + .GIT_COMMIT := $(.GIT_COMMIT)-dirty +endif + # docker manifest command will work with Docker CLI 18.03 or newer # but for now it's still experimental feature so we need to enable that export DOCKER_CLI_EXPERIMENTAL=enabled @@ -11,6 +17,13 @@ GOPATH := $(shell go env GOPATH) CODEGEN_VERSION := $(shell hack/print-codegen-version.sh) CODEGEN_PKG := $(GOPATH)/pkg/mod/k8s.io/code-generator@${CODEGEN_VERSION} +OWNER?=openfaas +REPOSITORY?="ghcr.io/$(OWNER)" +NAME := ingress-operator + +ARCH?=linux/amd64 +MULTIARCH?=linux/amd64,linux/arm/v7,linux/arm64 + $(TOOLS_DIR)/code-generator.mod: go.mod @echo "syncing code-generator tooling version" @cd $(TOOLS_DIR) && go mod edit -require "k8s.io/code-generator@${CODEGEN_VERSION}" @@ -19,34 +32,63 @@ ${CODEGEN_PKG}: $(TOOLS_DIR)/code-generator.mod @echo "(re)installing k8s.io/code-generator-${CODEGEN_VERSION}" @cd $(TOOLS_DIR) && go mod download -modfile=code-generator.mod +.PHONY: build build: - docker build -t ghcr.io/openfaas/ingress-operator:$(TAG)-amd64 . -f Dockerfile - docker build --build-arg OPTS="GOARCH=arm64" -t ghcr.io/openfaas/ingress-operator:$(TAG)-arm64 . -f Dockerfile - docker build --build-arg OPTS="GOARCH=arm GOARM=6" -t ghcr.io/openfaas/ingress-operator:$(TAG)-armhf . -f Dockerfile - -push: - docker push ghcr.io/openfaas/ingress-operator:$(TAG)-amd64 - docker push ghcr.io/openfaas/ingress-operator:$(TAG)-arm64 - docker push ghcr.io/openfaas/ingress-operator:$(TAG)-armhf - -manifest: - docker manifest create --amend ghcr.io/openfaas/ingress-operator:$(TAG) \ - ghcr.io/openfaas/ingress-operator:$(TAG)-amd64 \ - ghcr.io/openfaas/ingress-operator:$(TAG)-arm64 \ - ghcr.io/openfaas/ingress-operator:$(TAG)-armhf - docker manifest annotate ghcr.io/openfaas/ingress-operator:$(TAG) ghcr.io/openfaas/ingress-operator:$(TAG)-arm64 --os linux --arch arm64 - docker manifest annotate ghcr.io/openfaas/ingress-operator:$(TAG) ghcr.io/openfaas/ingress-operator:$(TAG)-armhf --os linux --arch arm --variant v6 - docker manifest push -p ghcr.io/openfaas/ingress-operator:$(TAG) + @echo "building $(REPOSITORY)/$(NAME):$(TAG)" + @docker build \ + --build-arg VERSION=$(.GIT_VERSION) \ + --build-arg GIT_COMMIT=$(.GIT_COMMIT) \ + -t $(REPOSITORY)/$(NAME):$(TAG) . + +.PHONY: build-buildx +build-buildx: + @echo $(REPOSITORY)/$(NAME):$(TAG) && \ + docker buildx create --use --name=multiarch --node=multiarch && \ + docker buildx build \ + --push \ + --platform $(ARCH) \ + --build-arg VERSION=$(.GIT_VERSION) \ + --build-arg GIT_COMMIT=$(.GIT_COMMIT) \ + --tag $(REPOSITORY)/$(NAME):$(TAG) \ + . + +.PHONY: build-buildx-all +build-buildx-all: + @echo "build $(REPOSITORY)/$(NAME):$(TAG) for $(MULTIARCH)" + @docker buildx create --use --name=multiarch --node=multiarch && \ + docker buildx build \ + --platform $(MULTIARCH) \ + --output "type=image,push=false" \ + --build-arg VERSION=$(.GIT_VERSION) \ + --build-arg GIT_COMMIT=$(.GIT_COMMIT) \ + --tag $(REPOSITORY)/$(NAME):$(TAG) \ + . + +.PHONY: publish-buildx-all +publish-buildx-all: + @echo "build and publish $(REPOSITORY)/$(NAME):$(TAG) for $(MULTIARCH)" + @docker buildx create --use --name=multiarch --node=multiarch && \ + docker buildx build \ + --platform $(MULTIARCH) \ + --push=true \ + --build-arg VERSION=$(.GIT_VERSION) \ + --build-arg GIT_COMMIT=$(.GIT_COMMIT) \ + --tag $(REPOSITORY)/$(NAME):$(TAG) \ + . +.PHONY: test test: go test -v ./... +.PHONY: verify-codegen verify-codegen: ${CODEGEN_PKG} ./hack/verify-codegen.sh +.PHONY: update-codegen update-codegen: ${CODEGEN_PKG} ./hack/update-codegen.sh +.PHONY: charts charts: cd chart && helm package ingress-operator/ mv chart/*.tgz docs/ diff --git a/main.go b/main.go index be570c4b..77c2674f 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,7 @@ package main import ( "flag" "os" + "strings" "time" clientset "github.com/openfaas-incubator/ingress-operator/pkg/client/clientset/versioned" @@ -85,11 +86,13 @@ func main() { faasInformerFactory := informers. NewSharedInformerFactoryWithOptions(faasClient, defaultResync, faasInformerOpt) - capabilities, err := getCapabilities(kubeClient) + capabilities, err := getPreferredAvailableAPIs(kubeClient, "Ingress") if err != nil { klog.Fatalf("Error retrieving Kubernetes cluster capabilities: %s", err.Error()) } + klog.Infof("cluster supports ingress in: %s", capabilities) + var ctrl controller if capabilities.Has("extensions/v1beta1") { ctrl = controllerv1beta1.NewController( @@ -139,6 +142,15 @@ func (c Capabilities) Has(wanted string) bool { return c[wanted] } +func (c Capabilities) String() string { + keys := make([]string, 0, len(c)) + for k := range c { + keys = append(keys, k) + } + return strings.Join(keys, ", ") +} + +// getCapabilities returns the list of available api groups in the cluster. func getCapabilities(client kubernetes.Interface) (Capabilities, error) { groupList, err := client.Discovery().ServerGroups() @@ -155,3 +167,32 @@ func getCapabilities(client kubernetes.Interface) (Capabilities, error) { return caps, nil } + +// getPreferredAvailableAPIs queries the cluster for the preferred resources information and returns a Capabilities +// instance containing those api groups that support the specified kind. +// +// kind should be the title case singular name of the kind. For example, "Ingress" is the kind for a resource "ingress". +func getPreferredAvailableAPIs(client kubernetes.Interface, kind string) (Capabilities, error) { + discoveryclient := client.Discovery() + lists, err := discoveryclient.ServerPreferredResources() + if err != nil { + return nil, err + } + + caps := Capabilities{} + for _, list := range lists { + if len(list.APIResources) == 0 { + continue + } + for _, resource := range list.APIResources { + if len(resource.Verbs) == 0 { + continue + } + if resource.Kind == kind { + caps[list.GroupVersion] = true + } + } + } + + return caps, nil +}