kube-updater: add Dockerfile & GHA pipelines (#22983)

This commit is contained in:
Hugo Shaka
2023-03-22 13:05:02 +00:00
committed by GitHub
parent d5c9eaea76
commit 5040fbda56
16 changed files with 121 additions and 95 deletions
@@ -8,32 +8,38 @@
#
# Note both workflows must have the same name.
name: Unit Tests (Operator)
run-name: Skip Unit Tests (Operator) - ${{ github.run_id }} - @${{ github.actor }}
name: Unit Tests (Integrations)
run-name: Skip Unit Tests (Integrations) - ${{ github.run_id }} - @${{ github.actor }}
on:
pull_request:
paths-ignore:
- '/go.mod'
- '/go.sum'
- 'integrations/operator/**'
- 'integrations/**'
- 'api/types/**'
- 'gen/**'
- 'lib/tbot/**'
- 'Makefile'
- '.github/workflows/unit-tests-integrations.yaml'
- 'build.assets/Makefile'
- 'build.assets/Dockerfile*'
merge_group:
paths-ignore:
- '/go.mod'
- '/go.sum'
- 'integrations/operator/**'
- 'integrations/**'
- 'api/types/**'
- 'gen/**'
- 'lib/tbot/**'
- 'Makefile'
- '.github/workflows/unit-tests-integrations.yaml'
- 'build.assets/Makefile'
- 'build.assets/Dockerfile*'
jobs:
test:
name: Unit Tests (Operator)
name: Unit Tests (Integrations)
runs-on: ubuntu-latest
permissions:
@@ -1,5 +1,5 @@
name: Unit Tests (Operator)
run-name: Unit Tests (Operator) - ${{ github.run_id }} - @${{ github.actor }}
name: Unit Tests (Integrations)
run-name: Unit Tests (Integrations) - ${{ github.run_id }} - @${{ github.actor }}
on:
push:
@@ -9,26 +9,30 @@ on:
paths:
- '/go.mod'
- '/go.sum'
- 'integrations/operator/**'
- 'integrations/**'
- 'api/types/**'
- 'gen/**'
- 'lib/tbot/**'
- 'Makefile'
- '.github/workflows/unit-tests-integrations.yaml'
- 'build.assets/Makefile'
- 'build.assets/Dockerfile*'
merge_group:
paths:
- '/go.mod'
- '/go.sum'
- 'integrations/operator/**'
- 'integrations/**'
- 'api/types/**'
- 'gen/**'
- 'lib/tbot/**'
- 'Makefile'
- '.github/workflows/unit-tests-integrations.yaml'
- 'build.assets/Makefile'
- 'build.assets/Dockerfile*'
jobs:
test:
name: Unit Tests (Operator)
name: Unit Tests (Integrations)
if: ${{ !startsWith(github.head_ref, 'dependabot/') }}
runs-on: ubuntu-22.04-16core
@@ -46,6 +50,10 @@ jobs:
- name: Prepare workspace
uses: ./.github/actions/prepare-workspace
- name: Run tests
- name: Run operator tests
timeout-minutes: 40
run: make test-operator
- name: Run kube-agent-updater tests
timeout-minutes: 15
run: make test-kube-agent-updater
+6 -1
View File
@@ -746,7 +746,7 @@ integration-root: $(TEST_LOG_DIR) $(RENDER_TESTS)
# changes (or last commit).
#
.PHONY: lint
lint: lint-sh lint-helm lint-api lint-go lint-license lint-rust lint-tools lint-protos
lint: lint-sh lint-helm lint-api lint-kube-agent-updater lint-go lint-license lint-rust lint-tools lint-protos
.PHONY: lint-tools
lint-tools: lint-build-tooling lint-backport
@@ -800,6 +800,11 @@ lint-api: GO_LINT_API_FLAGS ?=
lint-api:
cd api && golangci-lint run -c ../.golangci.yml $(GO_LINT_API_FLAGS)
.PHONY: lint-kube-agent-updater
lint-kube-agent-updater: GO_LINT_API_FLAGS ?=
lint-kube-agent-updater:
cd integrations/kube-agent-updater && golangci-lint run -c ../../.golangci.yml $(GO_LINT_API_FLAGS)
# TODO(awly): remove the `--exclude` flag after cleaning up existing scripts
.PHONY: lint-sh
lint-sh: SH_LINT_FLAGS ?=
@@ -0,0 +1,36 @@
ARG BUILDBOX
# BUILDPLATFORM is provided by Docker/buildx
FROM --platform=$BUILDPLATFORM $BUILDBOX as builder
WORKDIR /go/src/github.com/gravitational/teleport/integrations/kube-agent-updater
# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum
# Download and Cache dependencies before building and copying source
# This will prevent re-downloading the operator's dependencies if they have not changed as this
# `run` layer will be cached
RUN go mod download
COPY cmd/ cmd/
COPY pkg/ pkg/
# Compiler package should use host-triplet-agnostic name (i.e. "x86-64-linux-gnu-gcc" instead of "gcc")
# in most cases, to avoid issues on systems with multiple versions of gcc (i.e. buildboxes)
# TARGETOS and TARGETARCH are provided by Docker/buildx, but must be explicitly listed here
ARG COMPILER_NAME TARGETOS TARGETARCH
# Build the program
# CGO is required for github.com/gravitational/teleport/lib/system
RUN echo "Targeting $TARGETOS/$TARGETARCH with CC=$COMPILER_NAME" && \
CGO_ENABLED=1 CC=$COMPILER_NAME GOOS=$TARGETOS GOARCH=$TARGETARCH \
go build -a -o /go/bin/teleport-kube-agent-updater github.com/gravitational/teleport/integrations/kube-agent-updater/cmd/teleport-kube-agent-updater
# Create the image with the build operator on the $TARGETPLATFORM
# TARGETPLATFORM is provided by Docker/buildx
FROM --platform=$TARGETPLATFORM gcr.io/distroless/cc
WORKDIR /
COPY --from=builder /go/bin/teleport-kube-agent-updater .
ENTRYPOINT ["/teleport-kube-agent-updater"]
+34 -1
View File
@@ -1,7 +1,40 @@
.PHONY: test
# Image URL to use all building/pushing image targets
IMG ?= teleport-kube-agent-updater:latest
# include BUILDBOX_VERSION, BUILDBOX and BUILDBOX_variant variables
include ../../build.assets/images.mk
# Configure which compiler and buildbox to use
OS ?= $(shell go env GOOS)
ARCH ?= $(shell go env GOARCH)
ifeq ("$(OS)","linux")
ifeq ("$(ARCH)","amd64")
COMPILER ?= x86_64-linux-gnu-gcc
PLATFORM_BUILDBOX ?= $(BUILDBOX)
else ifeq ("$(ARCH)","386")
COMPILER ?= x86_64-linux-gnu-gcc
PLATFORM_BUILDBOX ?= $(BUILDBOX)
else ifeq ("$(ARCH)","arm")
COMPILER ?= arm-linux-gnueabihf-gcc
PLATFORM_BUILDBOX ?= $(BUILDBOX_ARM)
else ifeq ("$(ARCH)","arm64")
COMPILER ?= aarch64-linux-gnu-gcc
PLATFORM_BUILDBOX ?= $(BUILDBOX_ARM)
endif
endif
.PHONY: test
test: pkg/img/cosign_fixtures_test.go
go test ./...
.PHONY: docker-build
docker-build: ## Build docker image
docker buildx build --platform="$(OS)/$(ARCH)" --build-arg BUILDBOX=$(PLATFORM_BUILDBOX) \
--build-arg COMPILER_NAME=$(COMPILER) -t ${IMG} --load ./ -f ./Dockerfile
.PHONY: docker-push
docker-push: ## Push docker image
docker push ${IMG}
pkg/img/cosign_fixtures_test.go: hack/cosign-fixtures.go
go run hack/cosign-fixtures.go | gofmt > pkg/img/cosign_fixtures_test.go
@@ -43,10 +43,6 @@ var (
scheme = runtime.NewScheme()
)
const (
namespace = "namespace"
)
func init() {
SchemeBuilder.Register(
&appsv1.Deployment{},
@@ -418,6 +418,9 @@ func renderFixtures(keys *cosign.KeysBytes, layers []v1.Layer, manifests map[str
return "", trace.Wrap(err)
}
contentReader, err := layer.Uncompressed()
if err != nil {
return "", trace.Wrap(err)
}
content, err := io.ReadAll(contentReader)
if err != nil {
return "", trace.Wrap(err)
@@ -472,7 +475,7 @@ func generateSignedManifest(scenario string, signer digestedRefSigner, keys ...*
Layers: []v1.Descriptor{layerDesc},
}
// Generatin a manifest referencing the test layers
// Generating a manifest referencing the test layers
_, _, manifestDigest, err := contentSizeAndHash(manifest)
if err != nil {
return nil, nil, v1.Hash{}, trace.Wrap(err)
@@ -531,6 +534,9 @@ func generateSignedIndex(scenario string, signer digestedRefSigner, keys ...*cos
Architecture: "amd64",
OS: "linux",
})
if err != nil {
return nil, nil, v1.Hash{}, trace.Wrap(err)
}
// Referencing both manifests in an index
index := v1.IndexManifest{
@@ -36,7 +36,7 @@ type ServerMock struct {
path string
}
// SetResponse sets the ServerMock's reponse.
// SetResponse sets the ServerMock's response.
func (m *ServerMock) SetResponse(t *testing.T, code int, response string) {
m.t = t
m.code = code
@@ -17,74 +17,9 @@ limitations under the License.
package controller
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"golang.org/x/exp/rand"
appsv1 "k8s.io/api/apps/v1"
core "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
corescheme "k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
kclient "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
"sigs.k8s.io/controller-runtime/pkg/manager"
runtimescheme "sigs.k8s.io/controller-runtime/pkg/scheme"
)
var (
SchemeBuilder = &runtimescheme.Builder{GroupVersion: appsv1.SchemeGroupVersion}
scheme = runtime.NewScheme()
)
func init() {
SchemeBuilder.Register(
&appsv1.Deployment{},
&appsv1.DeploymentList{},
&appsv1.StatefulSet{},
&appsv1.StatefulSetList{},
)
utilruntime.Must(SchemeBuilder.AddToScheme(scheme))
}
func setupTest(t *testing.T) (manager.Manager, kclient.Client, string) {
testEnv := &envtest.Environment{}
cfg, err := testEnv.Start()
require.NoError(t, err)
require.NotNil(t, cfg)
namespace := validRandomResourceName("ns-")
k8sClient, err := kclient.New(cfg, kclient.Options{Scheme: corescheme.Scheme})
require.NoError(t, err)
ns := &core.Namespace{
ObjectMeta: metav1.ObjectMeta{Name: namespace},
}
ctx := context.Background()
err = k8sClient.Create(ctx, ns)
require.NoError(t, err)
t.Cleanup(func() {
err = testEnv.Stop()
require.NoError(t, err)
})
mgr, err := ctrl.NewManager(cfg, ctrl.Options{
Scheme: scheme,
MetricsBindAddress: "0",
})
require.NoError(t, err)
return mgr, k8sClient, namespace
}
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyz1234567890")
func validRandomResourceName(prefix string) string {
@@ -65,6 +65,7 @@ func Test_cosignKeyValidator_ValidateAndResolveDigest(t *testing.T) {
resp, err := testRegistry.Client().Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusCreated, resp.StatusCode)
require.NoError(t, resp.Body.Close())
}
for manifest, contents := range manifests {
u, err := url.Parse(testRegistry.URL + "/v2/testrepo/manifests/" + manifest)
@@ -77,10 +78,11 @@ func Test_cosignKeyValidator_ValidateAndResolveDigest(t *testing.T) {
resp, err := testRegistry.Client().Do(req)
require.NoError(t, err)
require.Equal(t, http.StatusCreated, resp.StatusCode)
require.NoError(t, resp.Body.Close())
}
// Build a validator
pubKey, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(publicKey))
pubKey, err := cryptoutils.UnmarshalPEMToPublicKey(publicKey)
require.NoError(t, err)
skid, err := cryptoutils.SKID(pubKey)
require.NoError(t, err)
@@ -43,5 +43,4 @@ limitations under the License.
// `teleport/integrations/kube-agent-updater/hack/cosign-fixtures.go`. The
// executable generates a go file declaring all blobs and manifests to be
// loaded in the test registry.
package img
@@ -34,8 +34,8 @@ const basicHTTPTestPath = "/v1/cloud-stable"
func Test_basicHTTPMaintenanceClient_Get(t *testing.T) {
mock := basichttp.NewServerMock(basicHTTPTestPath + "/" + constants.MaintenancePath)
t.Cleanup(mock.Srv.Close)
serverUrl, err := url.Parse(mock.Srv.URL)
serverUrl.Path = basicHTTPTestPath
serverURL, err := url.Parse(mock.Srv.URL)
serverURL.Path = basicHTTPTestPath
require.NoError(t, err)
ctx := context.Background()
@@ -94,7 +94,7 @@ func Test_basicHTTPMaintenanceClient_Get(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b := &basicHTTPMaintenanceClient{
baseURL: serverUrl,
baseURL: serverURL,
client: &basichttp.Client{Client: mock.Srv.Client()},
}
mock.SetResponse(t, tt.statusCode, tt.response)
@@ -39,7 +39,7 @@ func (m TriggerMock) CanStart(_ context.Context, _ client.Object) (bool, error)
return m.canStart, nil
}
// Default returns the default behaviour if the trigger fails. This cannot
// Default returns the default behavior if the trigger fails. This cannot
// happen for a TriggerMock and is here solely to implement the Trigger
// interface.
func (m TriggerMock) Default() bool {
@@ -97,7 +97,7 @@ type kubeScheduleRepr struct {
// it has no upcoming or ongoing maintenance window, or if it contains a window
// whose start is after its end. This could happen if the agent looses
// connectivity to its cluster or if we have a bug in the window calculation.
// In this case we don't want to honour the schedule and will consider the
// In this case we don't want to honor the schedule and will consider the
// agent is not working properly.
func (s kubeScheduleRepr) isValid(now time.Time) bool {
valid := false
@@ -34,8 +34,8 @@ const basicHTTPTestPath = "/v1/cloud-stable"
func Test_basicHTTPVersionClient_Get(t *testing.T) {
mock := basichttp.NewServerMock(basicHTTPTestPath + "/" + constants.VersionPath)
t.Cleanup(mock.Srv.Close)
serverUrl, err := url.Parse(mock.Srv.URL)
serverUrl.Path = basicHTTPTestPath
serverURL, err := url.Parse(mock.Srv.URL)
serverURL.Path = basicHTTPTestPath
require.NoError(t, err)
ctx := context.Background()
@@ -89,7 +89,7 @@ func Test_basicHTTPVersionClient_Get(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b := &basicHTTPVersionClient{
baseURL: serverUrl,
baseURL: serverURL,
client: &basichttp.Client{Client: mock.Srv.Client()},
}
mock.SetResponse(t, tt.statusCode, tt.response)
@@ -39,7 +39,7 @@ func ValidVersionChange(ctx context.Context, current, next string) bool {
log := ctrllog.FromContext(ctx).V(1)
// Cannot upgrade to a non-valid version
if !semver.IsValid(next) {
log.Error(trace.BadParameter("next verison is not following semver"), "version change is invalid", "nextVersion", next)
log.Error(trace.BadParameter("next version is not following semver"), "version change is invalid", "nextVersion", next)
return false
}
switch semver.Compare(next, current) {