mirror of
https://github.com/gravitational/teleport.git
synced 2026-09-24 16:17:11 +08:00
kube-updater: add Dockerfile & GHA pipelines (#22983)
This commit is contained in:
+11
-5
@@ -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:
|
||||
+14
-6
@@ -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
|
||||
@@ -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"]
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user