mirror of
https://github.com/gravitational/teleport.git
synced 2026-10-30 18:29:21 +08:00
Add a version server in the proxy + use it in agent chart (#35150)
This PR adds an embedded [version server](https://goteleport.com/docs/architecture/agent-update-management/#version-server-and-source-of-truth) in the proxy to address: https://github.com/gravitational/cloud/issues/6773 The version server can be configured through `teleport.yaml`: ```yaml proxy_service: enabled: "yes" automatic_upgrades_channels: stable/cloud: forward_url: https://updates.releases.teleport.dev/v1/stable/cloud preview/cloud: static_version: v12.5.4 ``` The forwarded call results are cached for a minute.
This commit is contained in:
@@ -133,29 +133,6 @@ updates:
|
||||
- "go"
|
||||
- "no-changelog"
|
||||
|
||||
- package-ecosystem: gomod
|
||||
directory: "/integrations/kube-agent-updater"
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: "sunday"
|
||||
time: "09:00" # 9am UTC
|
||||
open-pull-requests-limit: 10
|
||||
groups:
|
||||
go:
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
reviewers:
|
||||
- codingllama
|
||||
- hugoShaka
|
||||
- jentfoo
|
||||
- rosstimothy
|
||||
- zmb3
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "go"
|
||||
- "no-changelog"
|
||||
|
||||
- package-ecosystem: cargo
|
||||
directory: "/"
|
||||
schedule:
|
||||
|
||||
@@ -79,7 +79,7 @@ jobs:
|
||||
- name: Run base difftest
|
||||
uses: ./.github/actions/difftest
|
||||
with:
|
||||
flags: --skip="${{ steps.find_excluded.outputs.FLAKE_SKIP }}" -e "integrations/operator/**/*" -e "tool/tsh/**/*" -e "integration/**/*" -e "build.assets/**/*" -e "lib/auth/webauthncli/**/*" -e "lib/auth/touchid/**/*" -e "api/**/*" -e "integrations/kube-agent-updater/**/*" -e "examples/teleport-usage/**/*" -e "integrations/access/**" -e "integrations/lib/**" -e "integrations/lib/backoff/backoff_test.go" -e "e2e/**/*"
|
||||
flags: --skip="${{ steps.find_excluded.outputs.FLAKE_SKIP }}" -e "integrations/operator/**/*" -e "tool/tsh/**/*" -e "integration/**/*" -e "build.assets/**/*" -e "lib/auth/webauthncli/**/*" -e "lib/auth/touchid/**/*" -e "api/**/*" -e "examples/teleport-usage/**/*" -e "integrations/access/**" -e "integrations/lib/**" -e "integrations/lib/backoff/backoff_test.go" -e "e2e/**/*"
|
||||
target: test-go-unit
|
||||
|
||||
- name: Run touch-id difftest
|
||||
@@ -100,12 +100,6 @@ jobs:
|
||||
flags: --skip="${{ steps.find_excluded.outputs.FLAKE_SKIP }}" --include "api/**/*" --relative "api"
|
||||
target: test-api
|
||||
|
||||
- name: Run kube-agent-updater difftest
|
||||
uses: ./.github/actions/difftest
|
||||
with:
|
||||
flags: --skip="${{ steps.find_excluded.outputs.FLAKE_SKIP }}" --include "integrations/kube-agent-updater/**/*" --relative "integrations/kube-agent-updater"
|
||||
target: test-kube-agent-updater
|
||||
|
||||
- name: Run teleport-usage difftest
|
||||
uses: ./.github/actions/difftest
|
||||
with:
|
||||
|
||||
@@ -51,12 +51,6 @@ jobs:
|
||||
version: ${{ env.GOLANGCI_LINT_VERSION }}
|
||||
args: --build-tags libfido2,piv
|
||||
skip-cache: true
|
||||
- name: golangci-lint (kube-agent-updater)
|
||||
uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0
|
||||
with:
|
||||
version: ${{ env.GOLANGCI_LINT_VERSION }}
|
||||
working-directory: integrations/kube-agent-updater
|
||||
skip-cache: true
|
||||
- name: golangci-lint (assets/backport)
|
||||
uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0
|
||||
with:
|
||||
|
||||
@@ -65,7 +65,7 @@ spec:
|
||||
- "--agent-name={{ .Release.Name }}"
|
||||
- "--agent-namespace={{ .Release.Namespace }}"
|
||||
- "--base-image={{ include "teleport-kube-agent.baseImage" . }}"
|
||||
- "--version-server={{ $updater.versionServer }}"
|
||||
- "--version-server={{ tpl $updater.versionServer . }}"
|
||||
- "--version-channel={{ $updater.releaseChannel }}"
|
||||
{{- if $updater.securityContext }}
|
||||
securityContext: {{- toYaml $updater.securityContext | nindent 10 }}
|
||||
|
||||
@@ -57,6 +57,16 @@ tests:
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: "--agent-namespace=my-namespace"
|
||||
- it: defaults the updater version server to the proxy address
|
||||
set:
|
||||
proxyAddr: proxy.teleport.example.com:443
|
||||
roles: "custom"
|
||||
updater:
|
||||
enabled: true
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].args
|
||||
content: "--version-server=https://proxy.teleport.example.com:443/v1/webapi/automaticupgrades/channel"
|
||||
- it: sets the updater version server
|
||||
values:
|
||||
- ../.lint/updater.yaml
|
||||
|
||||
@@ -160,7 +160,8 @@ updater:
|
||||
# `updater.versionServer` is the URL of the version server the agent fetches
|
||||
# the target version from. The complete version endpoint is built by
|
||||
# concatenating `versionServer` and `releaseChannel`.
|
||||
versionServer: "https://updates.releases.teleport.dev/v1/"
|
||||
# This field supports gotemplate.
|
||||
versionServer: "https://{{ .Values.proxyAddr }}/v1/webapi/automaticupgrades/channel"
|
||||
# Release channel the agent subscribes to.
|
||||
releaseChannel: "stable/cloud"
|
||||
image: public.ecr.aws/gravitational/teleport-kube-agent-updater
|
||||
|
||||
@@ -25,7 +25,7 @@ require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/sql/armsql v1.2.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/subscription/armsubscription v1.2.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161
|
||||
github.com/ClickHouse/ch-go v0.61.0
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.16.0
|
||||
github.com/HdrHistogram/hdrhistogram-go v1.1.2
|
||||
@@ -136,7 +136,7 @@ require (
|
||||
github.com/prometheus/client_golang v1.17.0
|
||||
github.com/prometheus/client_model v0.5.0
|
||||
github.com/prometheus/common v0.45.0
|
||||
github.com/redis/go-redis/v9 v9.0.2 // replaced
|
||||
github.com/redis/go-redis/v9 v9.3.0 // replaced
|
||||
github.com/russellhaering/gosaml2 v0.9.1
|
||||
github.com/russellhaering/goxmldsig v1.4.0
|
||||
github.com/sashabaranov/go-openai v1.17.9
|
||||
@@ -166,7 +166,7 @@ require (
|
||||
go.opentelemetry.io/otel/trace v1.21.0
|
||||
go.opentelemetry.io/proto/otlp v1.0.0
|
||||
golang.org/x/crypto v0.16.0
|
||||
golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d
|
||||
golang.org/x/mod v0.14.0
|
||||
golang.org/x/net v0.19.0
|
||||
golang.org/x/oauth2 v0.15.0
|
||||
@@ -195,7 +195,7 @@ require (
|
||||
k8s.io/component-base v0.28.4
|
||||
k8s.io/klog/v2 v2.110.1
|
||||
k8s.io/kubectl v0.28.4
|
||||
sigs.k8s.io/controller-runtime v0.15.3
|
||||
sigs.k8s.io/controller-runtime v0.16.1
|
||||
sigs.k8s.io/controller-tools v0.13.0
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
software.sslmate.com/src/go-pkcs12 v0.4.0
|
||||
@@ -208,6 +208,15 @@ require (
|
||||
github.com/mailgun/minheap v0.0.0-20170619185613-3dbe6c6bf55f // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Masterminds/sprig/v3 v3.2.3
|
||||
github.com/distribution/reference v0.5.0
|
||||
github.com/google/go-containerregistry v0.17.0
|
||||
github.com/opencontainers/go-digest v1.0.0
|
||||
github.com/sigstore/cosign/v2 v2.2.1
|
||||
github.com/sigstore/sigstore v1.7.5
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.110.10 // indirect
|
||||
cloud.google.com/go/longrunning v0.5.4 // indirect
|
||||
@@ -216,15 +225,17 @@ require (
|
||||
github.com/99designs/keyring v1.2.2 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0 // indirect
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0 // indirect
|
||||
github.com/BurntSushi/toml v1.1.0 // indirect
|
||||
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c // indirect
|
||||
github.com/MakeNowJust/heredoc v1.0.0 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.2.0 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
|
||||
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
|
||||
github.com/apache/arrow/go/v12 v12.0.1 // indirect
|
||||
github.com/apache/thrift v0.16.0 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 // indirect
|
||||
@@ -239,46 +250,64 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/blang/semver v3.5.1+incompatible // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/chai2010/gettext-go v1.0.2 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/coreos/pkg v0.0.0-20220810130054-c7d1c02cb6cf // indirect
|
||||
github.com/crewjam/httperr v0.2.0 // indirect
|
||||
github.com/danieljoos/wincred v1.1.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46 // indirect
|
||||
github.com/danieljoos/wincred v1.2.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/daviddengcn/go-colortext v1.0.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/digitorus/timestamp v0.0.0-20230902153158-687734543647 // indirect
|
||||
github.com/dlclark/regexp2 v1.9.0 // indirect
|
||||
github.com/dmarkham/enumer v1.5.9 // indirect
|
||||
github.com/docker/distribution v2.8.2+incompatible // indirect
|
||||
github.com/docker/cli v24.0.7+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
github.com/docker/docker v24.0.7+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.8.0 // indirect
|
||||
github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
|
||||
github.com/elastic/elastic-transport-go/v8 v8.3.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
||||
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
|
||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
|
||||
github.com/fatih/camelcase v1.0.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/form3tech-oss/jwt-go v3.2.5+incompatible // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/fvbommel/sortorder v1.1.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
|
||||
github.com/go-chi/chi v4.1.2+incompatible // indirect
|
||||
github.com/go-errors/errors v1.4.2 // indirect
|
||||
github.com/go-faster/city v1.0.1 // indirect
|
||||
github.com/go-faster/errors v0.7.0 // indirect
|
||||
github.com/go-jose/go-jose/v3 v3.0.1 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-logr/zapr v1.2.4 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||
github.com/go-openapi/analysis v0.21.4 // indirect
|
||||
github.com/go-openapi/errors v0.20.4 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.20.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
github.com/go-openapi/swag v0.22.3 // indirect
|
||||
github.com/go-openapi/loads v0.21.2 // indirect
|
||||
github.com/go-openapi/runtime v0.26.0 // indirect
|
||||
github.com/go-openapi/spec v0.20.9 // indirect
|
||||
github.com/go-openapi/strfmt v0.21.7 // indirect
|
||||
github.com/go-openapi/swag v0.22.4 // indirect
|
||||
github.com/go-openapi/validate v0.22.1 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.15.5 // indirect
|
||||
github.com/go-webauthn/x v0.1.5 // indirect
|
||||
github.com/gobuffalo/flect v1.0.2 // indirect
|
||||
github.com/goccy/go-json v0.10.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.0 // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect
|
||||
@@ -286,9 +315,9 @@ require (
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/certificate-transparency-go v1.1.2 // indirect
|
||||
github.com/google/certificate-transparency-go v1.1.7 // indirect
|
||||
github.com/google/flatbuffers v23.1.21+incompatible // indirect
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect
|
||||
github.com/google/go-tpm v0.9.0 // indirect
|
||||
github.com/google/go-tspi v0.3.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
@@ -299,11 +328,14 @@ require (
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.2.0.20220308023801-e4a6915ea237 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 // indirect
|
||||
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
|
||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect
|
||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
||||
github.com/imdario/mergo v0.3.13 // indirect
|
||||
github.com/hashicorp/hcl v1.0.1-vault-5 // indirect
|
||||
github.com/huandu/xstrings v1.3.3 // indirect
|
||||
github.com/imdario/mergo v0.3.16 // indirect
|
||||
github.com/in-toto/in-toto-golang v0.9.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
||||
github.com/jackc/pgio v1.0.0 // indirect
|
||||
@@ -315,6 +347,7 @@ require (
|
||||
github.com/jcmturner/gofork v1.7.6 // indirect
|
||||
github.com/jcmturner/goidentity/v6 v6.0.1 // indirect
|
||||
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
|
||||
github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/josharian/native v1.1.0 // indirect
|
||||
@@ -327,9 +360,11 @@ require (
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/lib/pq v1.10.4 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/letsencrypt/boulder v0.0.0-20231026200631-000cd05d5491 // indirect
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
||||
github.com/lithammer/dedent v1.1.0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
@@ -340,7 +375,10 @@ require (
|
||||
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 // indirect
|
||||
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 // indirect
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||
github.com/mitchellh/copystructure v1.0.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
||||
github.com/moby/spdystream v0.2.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
@@ -349,12 +387,16 @@ require (
|
||||
github.com/mtibben/percent v0.2.1 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
|
||||
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect
|
||||
github.com/nsf/termbox-go v1.1.1 // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/pascaldekloe/name v1.0.1 // indirect
|
||||
github.com/patrickmn/go-cache v0.0.0-20180815053127-5633e0862627 // indirect
|
||||
github.com/paulmach/orb v0.10.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.18 // indirect
|
||||
@@ -362,24 +404,41 @@ require (
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkg/xattr v0.4.9 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/pquerna/cachecontrol v0.1.0 // indirect
|
||||
github.com/prometheus/procfs v0.11.1 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
||||
github.com/rs/zerolog v1.28.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 // indirect
|
||||
github.com/sagikazarmark/locafero v0.3.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/sasha-s/go-deadlock v0.0.0-20180226215254-237a9547c8a5 // indirect
|
||||
github.com/sassoftware/relic v7.2.1+incompatible // indirect
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.7.0 // indirect
|
||||
github.com/segmentio/asm v1.2.0 // indirect
|
||||
github.com/segmentio/encoding v0.3.5 // indirect
|
||||
github.com/shabbyrobe/gocovmerge v0.0.0-20190829150210-3e036491d500 // indirect
|
||||
github.com/shibumi/go-pathspec v1.3.0 // indirect
|
||||
github.com/shopspring/decimal v1.3.1 // indirect
|
||||
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 // indirect
|
||||
github.com/siddontang/go-log v0.0.0-20180807004314-8d05993dda07 // indirect
|
||||
github.com/sigstore/rekor v1.3.3 // indirect
|
||||
github.com/sigstore/timestamp-authority v1.2.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.10.0 // indirect
|
||||
github.com/spf13/cast v1.5.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.17.0 // indirect
|
||||
github.com/stretchr/objx v0.5.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
|
||||
github.com/thales-e-security/pool v0.0.2 // indirect
|
||||
github.com/theupdateframework/go-tuf v0.6.1 // indirect
|
||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
|
||||
github.com/transparency-dev/merkle v0.0.2 // indirect
|
||||
github.com/vbatts/tar-split v0.11.5 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.1.2 // indirect
|
||||
@@ -396,22 +455,23 @@ require (
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.26.0 // indirect
|
||||
golang.org/x/tools v0.16.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect
|
||||
gopkg.in/go-jose/go-jose.v2 v2.6.1 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 // indirect
|
||||
k8s.io/component-helpers v0.28.4 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
|
||||
k8s.io/metrics v0.28.4 // indirect
|
||||
k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect
|
||||
sigs.k8s.io/kustomize/kustomize/v5 v5.0.4-0.20230601165947-6ce0bf390ce3 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect
|
||||
)
|
||||
|
||||
// Update also `ignore` in .github/dependabot.yml.
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Teleport
|
||||
* Copyright (C) 2023 Gravitational, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/gravitational/teleport/integration/helpers"
|
||||
"github.com/gravitational/teleport/integrations/kube-agent-updater/pkg/basichttp"
|
||||
"github.com/gravitational/teleport/integrations/kube-agent-updater/pkg/constants"
|
||||
"github.com/gravitational/teleport/lib/automaticupgrades"
|
||||
"github.com/gravitational/teleport/lib/service/servicecfg"
|
||||
"github.com/gravitational/teleport/lib/utils"
|
||||
)
|
||||
|
||||
func createProxyWithChannels(t *testing.T, channels automaticupgrades.Channels) string {
|
||||
require.NoError(t, channels.CheckAndSetDefaults())
|
||||
testDir := t.TempDir()
|
||||
|
||||
cfg := helpers.InstanceConfig{
|
||||
ClusterName: "root.example.com",
|
||||
HostID: uuid.New().String(),
|
||||
NodeName: helpers.Loopback,
|
||||
Log: utils.NewLoggerForTests(),
|
||||
}
|
||||
cfg.Listeners = helpers.SingleProxyPortSetup(t, &cfg.Fds)
|
||||
rc := helpers.NewInstance(t, cfg)
|
||||
|
||||
var err error
|
||||
rcConf := servicecfg.MakeDefaultConfig()
|
||||
rcConf.DataDir = filepath.Join(testDir, "data")
|
||||
rcConf.Auth.Enabled = true
|
||||
rcConf.Proxy.Enabled = true
|
||||
rcConf.SSH.Enabled = false
|
||||
rcConf.Proxy.DisableWebInterface = true
|
||||
rcConf.Version = "v3"
|
||||
rcConf.Proxy.AutomaticUpgradesChannels = channels
|
||||
|
||||
err = rc.CreateEx(t, nil, rcConf)
|
||||
require.NoError(t, err)
|
||||
err = rc.Start()
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
assert.NoError(t, rc.StopAll())
|
||||
})
|
||||
|
||||
return cfg.Listeners.Web
|
||||
}
|
||||
|
||||
func TestVersionServer(t *testing.T) {
|
||||
// Test setup
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
testVersion := "v12.2.6"
|
||||
testVersionMajorTooHigh := "v99.1.3"
|
||||
|
||||
staticChannel := "static/ok"
|
||||
staticHighChannel := "static/high"
|
||||
forwardChannel := "forward/ok"
|
||||
forwardHighChannel := "forward/high"
|
||||
forwardPath := "/version-server/"
|
||||
|
||||
upstreamServer := basichttp.NewServerMock(forwardPath + constants.VersionPath)
|
||||
upstreamServer.SetResponse(t, http.StatusOK, testVersion)
|
||||
upstreamHighServer := basichttp.NewServerMock(forwardPath + constants.VersionPath)
|
||||
upstreamHighServer.SetResponse(t, http.StatusOK, testVersionMajorTooHigh)
|
||||
|
||||
channels := automaticupgrades.Channels{
|
||||
staticChannel: {
|
||||
StaticVersion: testVersion,
|
||||
},
|
||||
staticHighChannel: {
|
||||
StaticVersion: testVersionMajorTooHigh,
|
||||
},
|
||||
forwardChannel: {
|
||||
ForwardURL: upstreamServer.Srv.URL + forwardPath,
|
||||
},
|
||||
forwardHighChannel: {
|
||||
ForwardURL: upstreamHighServer.Srv.URL + forwardPath,
|
||||
},
|
||||
}
|
||||
|
||||
proxyAddr := createProxyWithChannels(t, channels)
|
||||
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
httpClient := http.Client{Transport: tr}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
channel string
|
||||
expectedResponse string
|
||||
}{
|
||||
{
|
||||
name: "static version OK",
|
||||
channel: staticChannel,
|
||||
expectedResponse: testVersion,
|
||||
},
|
||||
{
|
||||
name: "static version too high",
|
||||
channel: staticHighChannel,
|
||||
expectedResponse: constants.NoVersion,
|
||||
},
|
||||
{
|
||||
name: "forward version OK",
|
||||
channel: forwardChannel,
|
||||
expectedResponse: testVersion,
|
||||
},
|
||||
{
|
||||
name: "forward version too high",
|
||||
channel: forwardHighChannel,
|
||||
expectedResponse: constants.NoVersion,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
channelUrl, err := url.Parse(
|
||||
fmt.Sprintf("https://%s/v1/webapi/automaticupgrades/channel/%s/version", proxyAddr, tt.channel),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, channelUrl.String(), nil)
|
||||
require.NoError(t, err)
|
||||
res, err := httpClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer res.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(res.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, http.StatusOK, res.StatusCode)
|
||||
require.Equal(t, tt.expectedResponse, string(body))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,7 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
|
||||
|
||||
kubeversionupdater "github.com/gravitational/teleport/integrations/kube-agent-updater"
|
||||
"github.com/gravitational/teleport/integrations/kube-agent-updater/pkg/controller"
|
||||
"github.com/gravitational/teleport/integrations/kube-agent-updater/pkg/img"
|
||||
"github.com/gravitational/teleport/integrations/kube-agent-updater/pkg/maintenance"
|
||||
@@ -184,6 +185,8 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
ctrl.Log.Info("starting the updater", "version", kubeversionupdater.Version, "url", versionServerURL.String())
|
||||
|
||||
if err := mgr.Start(ctx); err != nil {
|
||||
ctrl.Log.Error(err, "failed to start manager, exiting")
|
||||
os.Exit(1)
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
module github.com/gravitational/teleport/integrations/kube-agent-updater
|
||||
|
||||
go 1.21
|
||||
|
||||
toolchain go1.21.1
|
||||
|
||||
require (
|
||||
github.com/Masterminds/sprig/v3 v3.2.3
|
||||
github.com/distribution/reference v0.5.0
|
||||
github.com/google/go-containerregistry v0.17.0
|
||||
github.com/gravitational/trace v1.3.1
|
||||
github.com/jonboulle/clockwork v0.4.0
|
||||
github.com/opencontainers/go-digest v1.0.0
|
||||
github.com/sigstore/cosign/v2 v2.2.2
|
||||
github.com/sigstore/sigstore v1.7.6
|
||||
github.com/stretchr/testify v1.8.4
|
||||
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678
|
||||
golang.org/x/mod v0.14.0
|
||||
k8s.io/api v0.28.4
|
||||
k8s.io/apimachinery v0.28.4
|
||||
sigs.k8s.io/controller-runtime v0.16.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.2.0 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/blang/semver v3.5.1+incompatible // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
|
||||
github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect
|
||||
github.com/digitorus/timestamp v0.0.0-20230902153158-687734543647 // indirect
|
||||
github.com/docker/cli v24.0.7+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
github.com/docker/docker v24.0.7+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.8.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
||||
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/go-chi/chi v4.1.2+incompatible // indirect
|
||||
github.com/go-logr/logr v1.3.0 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-logr/zapr v1.2.4 // indirect
|
||||
github.com/go-openapi/analysis v0.21.4 // indirect
|
||||
github.com/go-openapi/errors v0.20.4 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.20.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
github.com/go-openapi/loads v0.21.2 // indirect
|
||||
github.com/go-openapi/runtime v0.26.0 // indirect
|
||||
github.com/go-openapi/spec v0.20.11 // indirect
|
||||
github.com/go-openapi/strfmt v0.21.8 // indirect
|
||||
github.com/go-openapi/swag v0.22.4 // indirect
|
||||
github.com/go-openapi/validate v0.22.3 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/certificate-transparency-go v1.1.7 // indirect
|
||||
github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/uuid v1.4.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.1-vault-5 // indirect
|
||||
github.com/huandu/xstrings v1.3.3 // indirect
|
||||
github.com/imdario/mergo v0.3.16 // indirect
|
||||
github.com/in-toto/in-toto-golang v0.9.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.17.2 // indirect
|
||||
github.com/letsencrypt/boulder v0.0.0-20231026200631-000cd05d5491 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_golang v1.17.0 // indirect
|
||||
github.com/prometheus/client_model v0.5.0 // indirect
|
||||
github.com/prometheus/common v0.45.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.3.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/sassoftware/relic v7.2.1+incompatible // indirect
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.7.0 // indirect
|
||||
github.com/shibumi/go-pathspec v1.3.0 // indirect
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/sigstore/rekor v1.3.4 // indirect
|
||||
github.com/sigstore/timestamp-authority v1.2.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.10.0 // indirect
|
||||
github.com/spf13/cast v1.5.1 // indirect
|
||||
github.com/spf13/cobra v1.8.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.17.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
|
||||
github.com/theupdateframework/go-tuf v0.7.0 // indirect
|
||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
|
||||
github.com/transparency-dev/merkle v0.0.2 // indirect
|
||||
github.com/vbatts/tar-split v0.11.5 // indirect
|
||||
go.mongodb.org/mongo-driver v1.12.1 // indirect
|
||||
go.opentelemetry.io/otel v1.21.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.21.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.21.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.26.0 // indirect
|
||||
golang.org/x/crypto v0.16.0 // indirect
|
||||
golang.org/x/net v0.19.0 // indirect
|
||||
golang.org/x/oauth2 v0.15.0 // indirect
|
||||
golang.org/x/sync v0.5.0 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
golang.org/x/term v0.15.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
gopkg.in/go-jose/go-jose.v2 v2.6.1 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.28.0 // indirect
|
||||
k8s.io/client-go v0.28.3 // indirect
|
||||
k8s.io/component-base v0.28.1 // indirect
|
||||
k8s.io/klog/v2 v2.100.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -31,4 +31,8 @@ const (
|
||||
VersionPath = "version"
|
||||
HTTPTimeout = 10 * time.Second
|
||||
CacheDuration = time.Minute
|
||||
|
||||
// NoVersion is returned by the version endpoint when there is no valid target version.
|
||||
// This can be caused by the target version being incompatible with the cluster version.
|
||||
NoVersion = "none"
|
||||
)
|
||||
|
||||
@@ -29,6 +29,8 @@ import (
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
kclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
ctrllog "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
|
||||
"github.com/gravitational/teleport/integrations/kube-agent-updater/pkg/version"
|
||||
)
|
||||
|
||||
// DeploymentVersionUpdater Reconciles a podSpec by changing its image
|
||||
@@ -76,7 +78,7 @@ func (r *DeploymentVersionUpdater) Reconcile(ctx context.Context, req ctrl.Reque
|
||||
|
||||
image, err := r.GetVersion(ctx, &obj, currentVersion)
|
||||
var (
|
||||
noNewVersionErr *NoNewVersionError
|
||||
noNewVersionErr *version.NoNewVersionError
|
||||
maintenanceErr *MaintenanceNotTriggeredError
|
||||
)
|
||||
switch {
|
||||
|
||||
@@ -18,10 +18,6 @@
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// MaintenanceNotTriggeredError indicates that no trigger returned true and the controller did not reconcile.
|
||||
type MaintenanceNotTriggeredError struct {
|
||||
Message string `json:"message"`
|
||||
@@ -34,18 +30,3 @@ func (e *MaintenanceNotTriggeredError) Error() string {
|
||||
}
|
||||
return "maintenance not triggered"
|
||||
}
|
||||
|
||||
// NoNewVersionError indicates that no new version was found and the controller did not reconcile.
|
||||
type NoNewVersionError struct {
|
||||
Message string `json:"message"`
|
||||
CurrentVersion string `json:"currentVersion"`
|
||||
NextVersion string `json:"nextVersion"`
|
||||
}
|
||||
|
||||
// Error returns log friendly description of an error
|
||||
func (e *NoNewVersionError) Error() string {
|
||||
if e.Message != "" {
|
||||
return e.Message
|
||||
}
|
||||
return fmt.Sprintf("no new version (current: %q, next: %q)", e.CurrentVersion, e.NextVersion)
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import (
|
||||
ctrllog "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
|
||||
"github.com/gravitational/teleport/integrations/kube-agent-updater/pkg/podutils"
|
||||
"github.com/gravitational/teleport/integrations/kube-agent-updater/pkg/version"
|
||||
)
|
||||
|
||||
type StatefulSetVersionUpdater struct {
|
||||
@@ -101,7 +102,7 @@ func (r *StatefulSetVersionUpdater) Reconcile(ctx context.Context, req ctrl.Requ
|
||||
|
||||
image, err := r.GetVersion(ctx, &obj, currentVersion)
|
||||
var (
|
||||
noNewVersionErr *NoNewVersionError
|
||||
noNewVersionErr *version.NoNewVersionError
|
||||
maintenanceErr *MaintenanceNotTriggeredError
|
||||
)
|
||||
switch {
|
||||
|
||||
@@ -63,7 +63,7 @@ func (r *VersionUpdater) GetVersion(ctx context.Context, obj client.Object, curr
|
||||
|
||||
log.Info("New version candidate", "nextVersion", nextVersion)
|
||||
if !version.ValidVersionChange(ctx, currentVersion, nextVersion) {
|
||||
return nil, &NoNewVersionError{CurrentVersion: currentVersion, NextVersion: nextVersion}
|
||||
return nil, &version.NoNewVersionError{CurrentVersion: currentVersion, NextVersion: nextVersion}
|
||||
}
|
||||
|
||||
log.Info("Version change is valid, building img candidate")
|
||||
|
||||
@@ -44,8 +44,8 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
alwaysTrigger = maintenance.NewMaintenanceTriggerMock("always trigger", true)
|
||||
neverTrigger = maintenance.NewMaintenanceTriggerMock("never trigger", false)
|
||||
alwaysTrigger = maintenance.NewMaintenanceStaticTrigger("always trigger", true)
|
||||
neverTrigger = maintenance.NewMaintenanceStaticTrigger("never trigger", false)
|
||||
alwaysValid = img.NewImageValidatorMock(
|
||||
"always",
|
||||
true,
|
||||
@@ -82,7 +82,7 @@ func Test_VersionUpdater_GetVersion(t *testing.T) {
|
||||
releaseRegistry: defaultTestRegistry,
|
||||
releasePath: defaultTestPath,
|
||||
currentVersion: versionMid,
|
||||
versionGetter: version.NewGetterMock(versionHigh, nil),
|
||||
versionGetter: version.NewStaticGetter(versionHigh, nil),
|
||||
maintenanceTriggers: []maintenance.Trigger{alwaysTrigger},
|
||||
imageCheckers: []img.Validator{alwaysValid},
|
||||
assertErr: require.NoError,
|
||||
@@ -93,7 +93,7 @@ func Test_VersionUpdater_GetVersion(t *testing.T) {
|
||||
releaseRegistry: defaultTestRegistry,
|
||||
releasePath: defaultTestPath,
|
||||
currentVersion: "",
|
||||
versionGetter: version.NewGetterMock(versionHigh, nil),
|
||||
versionGetter: version.NewStaticGetter(versionHigh, nil),
|
||||
maintenanceTriggers: []maintenance.Trigger{alwaysTrigger},
|
||||
imageCheckers: []img.Validator{alwaysValid},
|
||||
assertErr: require.NoError,
|
||||
@@ -104,10 +104,21 @@ func Test_VersionUpdater_GetVersion(t *testing.T) {
|
||||
releaseRegistry: defaultTestRegistry,
|
||||
releasePath: defaultTestPath,
|
||||
currentVersion: versionMid,
|
||||
versionGetter: version.NewGetterMock(versionMid, nil),
|
||||
versionGetter: version.NewStaticGetter(versionMid, nil),
|
||||
maintenanceTriggers: []maintenance.Trigger{alwaysTrigger},
|
||||
imageCheckers: []img.Validator{alwaysValid},
|
||||
assertErr: errorIsType(&NoNewVersionError{}),
|
||||
assertErr: errorIsType(&version.NoNewVersionError{}),
|
||||
expectedImage: "",
|
||||
},
|
||||
{
|
||||
name: "no version",
|
||||
releaseRegistry: defaultTestRegistry,
|
||||
releasePath: defaultTestPath,
|
||||
currentVersion: versionMid,
|
||||
versionGetter: version.NewStaticGetter("", &version.NoNewVersionError{Message: "version server did not advertise a version"}),
|
||||
maintenanceTriggers: []maintenance.Trigger{alwaysTrigger},
|
||||
imageCheckers: []img.Validator{alwaysValid},
|
||||
assertErr: errorIsType(&version.NoNewVersionError{}),
|
||||
expectedImage: "",
|
||||
},
|
||||
{
|
||||
@@ -115,7 +126,7 @@ func Test_VersionUpdater_GetVersion(t *testing.T) {
|
||||
releaseRegistry: defaultTestRegistry,
|
||||
releasePath: defaultTestPath,
|
||||
currentVersion: versionMid,
|
||||
versionGetter: version.NewGetterMock(versionHigh, nil),
|
||||
versionGetter: version.NewStaticGetter(versionHigh, nil),
|
||||
maintenanceTriggers: []maintenance.Trigger{neverTrigger},
|
||||
imageCheckers: []img.Validator{alwaysValid},
|
||||
assertErr: errorIsType(&MaintenanceNotTriggeredError{}),
|
||||
@@ -126,7 +137,7 @@ func Test_VersionUpdater_GetVersion(t *testing.T) {
|
||||
releaseRegistry: defaultTestRegistry,
|
||||
releasePath: defaultTestPath,
|
||||
currentVersion: versionMid,
|
||||
versionGetter: version.NewGetterMock(versionHigh, nil),
|
||||
versionGetter: version.NewStaticGetter(versionHigh, nil),
|
||||
maintenanceTriggers: []maintenance.Trigger{alwaysTrigger},
|
||||
imageCheckers: []img.Validator{neverValid},
|
||||
assertErr: errorIsType(&trace.TrustError{}),
|
||||
@@ -137,7 +148,7 @@ func Test_VersionUpdater_GetVersion(t *testing.T) {
|
||||
releaseRegistry: defaultTestRegistry,
|
||||
releasePath: defaultTestPath,
|
||||
currentVersion: versionMid,
|
||||
versionGetter: version.NewGetterMock("", &trace.ConnectionProblemError{}),
|
||||
versionGetter: version.NewStaticGetter("", &trace.ConnectionProblemError{}),
|
||||
maintenanceTriggers: []maintenance.Trigger{alwaysTrigger},
|
||||
imageCheckers: []img.Validator{neverValid},
|
||||
assertErr: errorIsType(&trace.ConnectionProblemError{}),
|
||||
@@ -161,7 +172,7 @@ func Test_VersionUpdater_GetVersion(t *testing.T) {
|
||||
baseImage: baseImage,
|
||||
}
|
||||
|
||||
// We need a dummy Kubernetes object, it is not used by the TriggerMock
|
||||
// We need a dummy Kubernetes object, it is not used by the StaticTrigger
|
||||
obj := &core.Pod{}
|
||||
|
||||
// Doing the test
|
||||
|
||||
@@ -24,33 +24,33 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
// TriggerMock is a fake Trigger that return a static answer. This is used
|
||||
// StaticTrigger is a fake Trigger that return a static answer. This is used
|
||||
// for testing purposes and is inherently disruptive.
|
||||
type TriggerMock struct {
|
||||
type StaticTrigger struct {
|
||||
name string
|
||||
canStart bool
|
||||
}
|
||||
|
||||
// Name returns the TriggerMock name.
|
||||
func (m TriggerMock) Name() string {
|
||||
// Name returns the StaticTrigger name.
|
||||
func (m StaticTrigger) Name() string {
|
||||
return m.name
|
||||
}
|
||||
|
||||
// CanStart returns the statically defined maintenance approval result.
|
||||
func (m TriggerMock) CanStart(_ context.Context, _ client.Object) (bool, error) {
|
||||
func (m StaticTrigger) CanStart(_ context.Context, _ client.Object) (bool, error) {
|
||||
return m.canStart, nil
|
||||
}
|
||||
|
||||
// Default returns the default behavior if the trigger fails. This cannot
|
||||
// happen for a TriggerMock and is here solely to implement the Trigger
|
||||
// happen for a StaticTrigger and is here solely to implement the Trigger
|
||||
// interface.
|
||||
func (m TriggerMock) Default() bool {
|
||||
func (m StaticTrigger) Default() bool {
|
||||
return m.canStart
|
||||
}
|
||||
|
||||
// NewMaintenanceTriggerMock creates a TriggerMock
|
||||
func NewMaintenanceTriggerMock(name string, canStart bool) Trigger {
|
||||
return TriggerMock{
|
||||
// NewMaintenanceStaticTrigger creates a StaticTrigger
|
||||
func NewMaintenanceStaticTrigger(name string, canStart bool) Trigger {
|
||||
return StaticTrigger{
|
||||
name: name,
|
||||
canStart: canStart,
|
||||
}
|
||||
|
||||
@@ -49,8 +49,12 @@ func (b *basicHTTPVersionClient) Get(ctx context.Context) (string, error) {
|
||||
if err != nil {
|
||||
return "", trace.Wrap(err)
|
||||
}
|
||||
response := string(body)
|
||||
if response == constants.NoVersion {
|
||||
return "", &NoNewVersionError{Message: "version server did not advertise a version"}
|
||||
}
|
||||
// We trim spaces because the value might end with one or many newlines
|
||||
version, err := EnsureSemver(strings.TrimSpace(string(body)))
|
||||
version, err := EnsureSemver(strings.TrimSpace(response))
|
||||
return version, trace.Wrap(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Teleport
|
||||
* Copyright (C) 2023 Gravitational, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package version
|
||||
|
||||
import "fmt"
|
||||
|
||||
// NoNewVersionError indicates that no new version was found and the controller did not reconcile.
|
||||
type NoNewVersionError struct {
|
||||
Message string `json:"message"`
|
||||
CurrentVersion string `json:"currentVersion"`
|
||||
NextVersion string `json:"nextVersion"`
|
||||
}
|
||||
|
||||
// Error returns log friendly description of an error
|
||||
func (e *NoNewVersionError) Error() string {
|
||||
if e.Message != "" {
|
||||
return e.Message
|
||||
}
|
||||
return fmt.Sprintf("no new version (current: %q, next: %q)", e.CurrentVersion, e.NextVersion)
|
||||
}
|
||||
@@ -23,25 +23,25 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GetterMock is a fake version.Getter that return a static answer. This is used
|
||||
// StaticGetter is a fake version.Getter that return a static answer. This is used
|
||||
// for testing purposes.
|
||||
type GetterMock struct {
|
||||
type StaticGetter struct {
|
||||
version string
|
||||
err error
|
||||
}
|
||||
|
||||
// GetVersion returns the statically defined version.
|
||||
func (v GetterMock) GetVersion(_ context.Context) (string, error) {
|
||||
func (v StaticGetter) GetVersion(_ context.Context) (string, error) {
|
||||
return v.version, v.err
|
||||
}
|
||||
|
||||
// NewGetterMock creates a GetterMock
|
||||
func NewGetterMock(version string, err error) Getter {
|
||||
// NewStaticGetter creates a StaticGetter
|
||||
func NewStaticGetter(version string, err error) Getter {
|
||||
semVersion := version
|
||||
if semVersion != "" && !strings.HasPrefix(semVersion, "v") {
|
||||
semVersion = "v" + version
|
||||
}
|
||||
return GetterMock{
|
||||
return StaticGetter{
|
||||
version: semVersion,
|
||||
err: err,
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ import (
|
||||
kclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
|
||||
|
||||
"github.com/gravitational/teleport/api/client"
|
||||
"github.com/gravitational/teleport/api/types"
|
||||
@@ -181,8 +182,8 @@ func (s *TestSetup) StartKubernetesOperator(t *testing.T) {
|
||||
}
|
||||
|
||||
k8sManager, err := ctrl.NewManager(s.K8sRestConfig, ctrl.Options{
|
||||
Scheme: scheme,
|
||||
MetricsBindAddress: "0",
|
||||
Scheme: scheme,
|
||||
Metrics: metricsserver.Options{BindAddress: "0"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/cache"
|
||||
"sigs.k8s.io/controller-runtime/pkg/healthz"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
|
||||
|
||||
resourcesv1 "github.com/gravitational/teleport/integrations/operator/apis/resources/v1"
|
||||
resourcesv2 "github.com/gravitational/teleport/integrations/operator/apis/resources/v2"
|
||||
@@ -100,8 +101,10 @@ func main() {
|
||||
}
|
||||
|
||||
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
|
||||
Scheme: scheme,
|
||||
MetricsBindAddress: config.metricsAddr,
|
||||
Scheme: scheme,
|
||||
Metrics: metricsserver.Options{
|
||||
BindAddress: config.metricsAddr,
|
||||
},
|
||||
HealthProbeBindAddress: config.probeAddr,
|
||||
LeaderElection: true,
|
||||
LeaderElectionID: config.leaderElectionID,
|
||||
@@ -109,7 +112,9 @@ func main() {
|
||||
PprofBindAddress: config.pprofAddr,
|
||||
Cache: cache.Options{
|
||||
SyncPeriod: &config.syncPeriod,
|
||||
Namespaces: []string{config.namespace},
|
||||
DefaultNamespaces: map[string]cache.Config{
|
||||
config.namespace: {},
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Teleport
|
||||
* Copyright (C) 2023 Gravitational, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package automaticupgrades
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
|
||||
"github.com/gravitational/teleport/integrations/kube-agent-updater/pkg/maintenance"
|
||||
"github.com/gravitational/teleport/integrations/kube-agent-updater/pkg/version"
|
||||
)
|
||||
|
||||
// Channels is a map of Channel objects.
|
||||
type Channels map[string]*Channel
|
||||
|
||||
// CheckAndSetDefaults checks that every Channel is valid and initializes them.
|
||||
func (c Channels) CheckAndSetDefaults() error {
|
||||
var errs []error
|
||||
var err error
|
||||
for name, channel := range c {
|
||||
// Wrapping is not mandatory here, but it adds the channel name in the
|
||||
// error, which makes troubleshooting easier.
|
||||
err = trace.Wrap(channel.CheckAndSetDefaults(), "failed to create channel %s", name)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
return trace.NewAggregate(errs...)
|
||||
}
|
||||
|
||||
// Channel describes an automatic update channel configuration.
|
||||
// It can be configured to serve a static version, or forward version requests
|
||||
// to an upstream version server. Forwarded results are cached for 1 minute.
|
||||
type Channel struct {
|
||||
// ForwardURL is the URL of the upstream version server providing the channel version/criticality.
|
||||
ForwardURL string `yaml:"forward_url,omitempty"`
|
||||
// StaticVersion is a static version the channel must serve. With or without the leading "v".
|
||||
StaticVersion string `yaml:"static_version,omitempty"`
|
||||
// Critical is whether the static version channel should be marked as a critical update.
|
||||
Critical bool `yaml:"critical"`
|
||||
|
||||
// versionGetter gets the version of the channel. It is populated by CheckAndSetDefaults.
|
||||
versionGetter version.Getter
|
||||
// criticalTrigger gets the criticality of the channel. It is populated by CheckAndSetDefaults.
|
||||
criticalTrigger maintenance.Trigger
|
||||
}
|
||||
|
||||
// CheckAndSetDefaults checks that the Channel configuration is valid and inits
|
||||
// the version getter and maintenance trigger of the Channel based on its
|
||||
// configuration. This function must be called before using the channel.
|
||||
func (c *Channel) CheckAndSetDefaults() error {
|
||||
switch {
|
||||
case c.ForwardURL != "" && (c.StaticVersion != "" || c.Critical):
|
||||
return trace.BadParameter("cannot set both ForwardURL and (StaticVersion or Critical)")
|
||||
case c.ForwardURL != "":
|
||||
baseURL, err := url.Parse(c.ForwardURL)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
c.versionGetter = version.NewBasicHTTPVersionGetter(baseURL)
|
||||
c.criticalTrigger = maintenance.NewBasicHTTPMaintenanceTrigger("remote", baseURL)
|
||||
case c.StaticVersion != "":
|
||||
c.versionGetter = version.NewStaticGetter(c.StaticVersion, nil)
|
||||
c.criticalTrigger = maintenance.NewMaintenanceStaticTrigger("remote", c.Critical)
|
||||
default:
|
||||
return trace.BadParameter("either ForwardURL or StaticVersion must be set")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetVersion returns the current version of the channel. If io is involved,
|
||||
// this function implements cache and is safe to call frequently.
|
||||
func (c *Channel) GetVersion(ctx context.Context) (string, error) {
|
||||
return c.versionGetter.GetVersion(ctx)
|
||||
}
|
||||
|
||||
// GetCritical returns the current criticality of the channel. If io is involved,
|
||||
// this function implements cache and is safe to call frequently.
|
||||
func (c *Channel) GetCritical(ctx context.Context) (bool, error) {
|
||||
return c.criticalTrigger.CanStart(ctx, nil)
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Teleport
|
||||
* Copyright (C) 2023 Gravitational, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package automaticupgrades
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/gravitational/teleport/integrations/kube-agent-updater/pkg/maintenance"
|
||||
"github.com/gravitational/teleport/integrations/kube-agent-updater/pkg/version"
|
||||
)
|
||||
|
||||
const testVersion = "v1.2.3"
|
||||
|
||||
func Test_Channels_CheckAndSetDefaults(t *testing.T) {
|
||||
t.Run("no channels", func(t *testing.T) {
|
||||
c := Channels{}
|
||||
require.NoError(t, c.CheckAndSetDefaults())
|
||||
})
|
||||
t.Run("single channel", func(t *testing.T) {
|
||||
channel := &Channel{StaticVersion: testVersion}
|
||||
c := Channels{"foo": channel}
|
||||
require.NoError(t, c.CheckAndSetDefaults())
|
||||
require.NotNil(t, channel.versionGetter)
|
||||
require.NotNil(t, channel.criticalTrigger)
|
||||
})
|
||||
t.Run("many channels", func(t *testing.T) {
|
||||
channel1 := &Channel{StaticVersion: testVersion}
|
||||
channel2 := &Channel{StaticVersion: testVersion}
|
||||
channel3 := &Channel{StaticVersion: testVersion}
|
||||
c := Channels{"foo": channel1, "bar": channel2, "baz": channel3}
|
||||
require.NoError(t, c.CheckAndSetDefaults())
|
||||
require.NotNil(t, channel1.versionGetter)
|
||||
require.NotNil(t, channel1.criticalTrigger)
|
||||
require.NotNil(t, channel2.versionGetter)
|
||||
require.NotNil(t, channel2.criticalTrigger)
|
||||
require.NotNil(t, channel3.versionGetter)
|
||||
require.NotNil(t, channel3.criticalTrigger)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Channel_CheckAndSetDefaults(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
channel Channel
|
||||
assertError require.ErrorAssertionFunc
|
||||
expectedVersionGetterType interface{}
|
||||
expectedCriticalTriggerType interface{}
|
||||
}{
|
||||
{
|
||||
name: "empty (invalid)",
|
||||
channel: Channel{},
|
||||
assertError: require.Error,
|
||||
},
|
||||
{
|
||||
name: "forward URL (valid)",
|
||||
channel: Channel{
|
||||
ForwardURL: stableCloudVersionBaseURL,
|
||||
},
|
||||
assertError: require.NoError,
|
||||
expectedVersionGetterType: version.BasicHTTPVersionGetter{},
|
||||
expectedCriticalTriggerType: maintenance.BasicHTTPMaintenanceTrigger{},
|
||||
},
|
||||
{
|
||||
name: "static version (valid)",
|
||||
channel: Channel{
|
||||
StaticVersion: testVersion,
|
||||
},
|
||||
assertError: require.NoError,
|
||||
expectedVersionGetterType: version.StaticGetter{},
|
||||
expectedCriticalTriggerType: maintenance.StaticTrigger{},
|
||||
},
|
||||
{
|
||||
name: "all set (invalid)",
|
||||
channel: Channel{
|
||||
ForwardURL: stableCloudVersionBaseURL,
|
||||
StaticVersion: testVersion,
|
||||
},
|
||||
assertError: require.Error,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tt.assertError(t, tt.channel.CheckAndSetDefaults())
|
||||
require.IsType(t, tt.expectedVersionGetterType, tt.channel.versionGetter)
|
||||
require.IsType(t, tt.expectedCriticalTriggerType, tt.channel.criticalTrigger)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1111,6 +1111,13 @@ func applyProxyConfig(fc *FileConfig, cfg *servicecfg.Config) error {
|
||||
cfg.Proxy.MySQLServerVersion = fc.Proxy.MySQLServerVersion
|
||||
}
|
||||
|
||||
if fc.Proxy.AutomaticUpgradesChannels != nil {
|
||||
cfg.Proxy.AutomaticUpgradesChannels = fc.Proxy.AutomaticUpgradesChannels
|
||||
if err := cfg.Proxy.AutomaticUpgradesChannels.CheckAndSetDefaults(); err != nil {
|
||||
return trace.Wrap(err, "failed to set up automatic update channels")
|
||||
}
|
||||
}
|
||||
|
||||
// This is the legacy format. Continue to support it forever, but ideally
|
||||
// users now use the list format below.
|
||||
if fc.Proxy.KeyFile != "" || fc.Proxy.CertFile != "" {
|
||||
|
||||
@@ -46,6 +46,7 @@ import (
|
||||
apiutils "github.com/gravitational/teleport/api/utils"
|
||||
"github.com/gravitational/teleport/api/utils/keys"
|
||||
"github.com/gravitational/teleport/api/utils/tlsutils"
|
||||
"github.com/gravitational/teleport/lib/automaticupgrades"
|
||||
"github.com/gravitational/teleport/lib/backend"
|
||||
"github.com/gravitational/teleport/lib/client"
|
||||
"github.com/gravitational/teleport/lib/defaults"
|
||||
@@ -2003,6 +2004,11 @@ type Proxy struct {
|
||||
// the "X-Forwarded-For" headers for web APIs received from layer 7 load
|
||||
// balancers or reverse proxies.
|
||||
TrustXForwardedFor types.Bool `yaml:"trust_x_forwarded_for,omitempty"`
|
||||
|
||||
// AutomaticUpgradesChannels is a map of all version channels used by the
|
||||
// proxy built-in version server to retrieve target versions. This is part
|
||||
// of the automatic upgrades.
|
||||
AutomaticUpgradesChannels automaticupgrades.Channels `yaml:"automatic_upgrades_channels,omitempty"`
|
||||
}
|
||||
|
||||
// UIConfig provides config options for the web UI served by the proxy service.
|
||||
|
||||
@@ -4051,11 +4051,12 @@ func (process *TeleportProcess) initProxyEndpoint(conn *Connector) error {
|
||||
ctx, err := controller(ctx, sctx, login, localAddr, remoteAddr)
|
||||
return ctx, trace.Wrap(err)
|
||||
}),
|
||||
PROXYSigner: proxySigner,
|
||||
OpenAIConfig: cfg.Testing.OpenAIConfig,
|
||||
NodeWatcher: nodeWatcher,
|
||||
AccessGraphAddr: accessGraphAddr,
|
||||
TracerProvider: process.TracingProvider,
|
||||
PROXYSigner: proxySigner,
|
||||
OpenAIConfig: cfg.Testing.OpenAIConfig,
|
||||
NodeWatcher: nodeWatcher,
|
||||
AccessGraphAddr: accessGraphAddr,
|
||||
TracerProvider: process.TracingProvider,
|
||||
AutomaticUpgradesChannels: cfg.Proxy.AutomaticUpgradesChannels,
|
||||
}
|
||||
webHandler, err := web.NewHandler(webConfig)
|
||||
if err != nil {
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"github.com/gravitational/trace"
|
||||
|
||||
"github.com/gravitational/teleport/api/client/webclient"
|
||||
"github.com/gravitational/teleport/lib/automaticupgrades"
|
||||
"github.com/gravitational/teleport/lib/defaults"
|
||||
"github.com/gravitational/teleport/lib/limiter"
|
||||
"github.com/gravitational/teleport/lib/multiplexer"
|
||||
@@ -156,6 +157,11 @@ type ProxyConfig struct {
|
||||
// as a label and used by reverse tunnel agents in proxy peering mode. Zero
|
||||
// is a valid generation.
|
||||
ProxyGroupGeneration uint64
|
||||
|
||||
// AutomaticUpgradesChannels is a map of all version channels used by the
|
||||
// proxy built-in version server to retrieve target versions. This is part
|
||||
// of the automatic upgrades.
|
||||
AutomaticUpgradesChannels automaticupgrades.Channels
|
||||
}
|
||||
|
||||
// WebPublicAddr returns the address for the web endpoint on this proxy that
|
||||
|
||||
@@ -293,6 +293,11 @@ type Config struct {
|
||||
|
||||
// AccessGraphAddr is the address of the Access Graph service GRPC API
|
||||
AccessGraphAddr utils.NetAddr
|
||||
|
||||
// AutomaticUpgradesChannels is a map of all version channels used by the
|
||||
// proxy built-in version server to retrieve target versions. This is part
|
||||
// of the automatic upgrades.
|
||||
AutomaticUpgradesChannels automaticupgrades.Channels
|
||||
}
|
||||
|
||||
// SetDefaults ensures proper default values are set if
|
||||
@@ -893,6 +898,10 @@ func (h *Handler) bindDefaultEndpoints() {
|
||||
// Returns logins included in the Connect My Computer role of the user.
|
||||
// Returns an empty list of logins if the user does not have a Connect My Computer role assigned.
|
||||
h.GET("/webapi/connectmycomputer/logins", h.WithAuth(h.connectMyComputerLoginsList))
|
||||
|
||||
// Implements the agent version server.
|
||||
// Channel can contain "/", hence the use of a catch-all parameter
|
||||
h.GET("/webapi/automaticupgrades/channel/*request", h.WithUnauthenticatedHighLimiter(h.automaticUpgrades))
|
||||
}
|
||||
|
||||
// GetProxyClient returns authenticated auth server client
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Teleport
|
||||
* Copyright (C) 2023 Gravitational, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package web
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"golang.org/x/mod/semver"
|
||||
|
||||
"github.com/gravitational/teleport"
|
||||
"github.com/gravitational/teleport/integrations/kube-agent-updater/pkg/constants"
|
||||
versionlib "github.com/gravitational/teleport/integrations/kube-agent-updater/pkg/version"
|
||||
"github.com/gravitational/teleport/lib/automaticupgrades"
|
||||
)
|
||||
|
||||
const defaultChannelTimeout = 5 * time.Second
|
||||
|
||||
// automaticUpgrades implements a version server in the Teleport Proxy.
|
||||
// It is configured through the Teleport Proxy configuration and tells agent updaters
|
||||
// which version they should install.
|
||||
func (h *Handler) automaticUpgrades(w http.ResponseWriter, r *http.Request, p httprouter.Params) (interface{}, error) {
|
||||
if h.cfg.AutomaticUpgradesChannels == nil {
|
||||
return nil, trace.AccessDenied("This proxy is not configured to serve automatic upgrades channels.")
|
||||
}
|
||||
|
||||
// The request format is "<channel name>/{version,critical}"
|
||||
// As <channel name> might contain "/" we have to split, pop the last part
|
||||
// and re-construct the channel name.
|
||||
channelAndType := p.ByName("request")
|
||||
|
||||
reqParts := strings.Split(strings.Trim(channelAndType, "/"), "/")
|
||||
if len(reqParts) < 2 {
|
||||
return nil, trace.BadParameter("path format should be /webapi/automaticupgrades/channel/<channel>/{version,critical}")
|
||||
}
|
||||
requestType := reqParts[len(reqParts)-1]
|
||||
channelName := strings.Join(reqParts[:len(reqParts)-1], "/")
|
||||
|
||||
if channelName == "" {
|
||||
return nil, trace.BadParameter("a channel name is required")
|
||||
}
|
||||
|
||||
// We check if the channel is configured
|
||||
channel, ok := h.cfg.AutomaticUpgradesChannels[channelName]
|
||||
if !ok {
|
||||
return nil, trace.NotFound("channel %s not found", channelName)
|
||||
}
|
||||
|
||||
// Finally, we treat the request based on its type
|
||||
switch requestType {
|
||||
case "version":
|
||||
h.log.Debugf("Agent requesting version for channel %s", channelName)
|
||||
return h.automaticUpgradesVersion(w, r, channel)
|
||||
case "critical":
|
||||
h.log.Debugf("Agent requesting criticality for channel %s", channelName)
|
||||
return h.automaticUpgradesCritical(w, r, channel)
|
||||
default:
|
||||
return nil, trace.BadParameter("requestType path must end with 'version' or 'critical'")
|
||||
}
|
||||
}
|
||||
|
||||
// automaticUpgradesVersion handles version requests from upgraders
|
||||
func (h *Handler) automaticUpgradesVersion(w http.ResponseWriter, r *http.Request, channel *automaticupgrades.Channel) (interface{}, error) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), defaultChannelTimeout)
|
||||
defer cancel()
|
||||
|
||||
targetVersion, err := channel.GetVersion(ctx)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
// We don't want to tell the updater to upgrade to a new major we don't support yet
|
||||
// This is mainly a workaround for Teleport Cloud and might be removed
|
||||
// In the future when we'll have better tooling to control version channels.
|
||||
targetMajor, err := parseMajorFromVersionString(targetVersion)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err, "failed to process target version")
|
||||
}
|
||||
|
||||
teleportMajor, err := parseMajorFromVersionString(teleport.Version)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err, "failed to process teleport version")
|
||||
}
|
||||
|
||||
if targetMajor > teleportMajor {
|
||||
_, err = w.Write([]byte(constants.NoVersion))
|
||||
h.log.Debugf("Client hit channel %s, target version (%s) major is above the proxy major (%s). Ignoring update.")
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte(targetVersion))
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
// automaticUpgradesCritical handles criticality requests from upgraders
|
||||
func (h *Handler) automaticUpgradesCritical(w http.ResponseWriter, r *http.Request, channel *automaticupgrades.Channel) (interface{}, error) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), defaultChannelTimeout)
|
||||
defer cancel()
|
||||
|
||||
critical, err := channel.GetCritical(ctx)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
response := "no"
|
||||
if critical {
|
||||
response = "yes"
|
||||
}
|
||||
_, err = w.Write([]byte(response))
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
func parseMajorFromVersionString(version string) (int, error) {
|
||||
version, err := versionlib.EnsureSemver(version)
|
||||
if err != nil {
|
||||
return 0, trace.Wrap(err, "invalid semver: %s", version)
|
||||
}
|
||||
majorStr := semver.Major(version)
|
||||
if majorStr == "" {
|
||||
return 0, trace.BadParameter("cannot detect version major")
|
||||
}
|
||||
|
||||
major, err := strconv.Atoi(strings.TrimPrefix(majorStr, "v"))
|
||||
return major, trace.Wrap(err, "cannot convert version major to int")
|
||||
}
|
||||
Reference in New Issue
Block a user