Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 18 additions & 7 deletions cmd/ate-setup/internal/steps/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ func (e *Env) DeployAteAPIServer(ctx context.Context) error {
return err
}
}
manifest, err := e.renderResolve(ctx, e.Cfg.Manifest("ate-api-server.yaml"))
manifest, err := e.renderResolve(ctx, e.apiServerManifestPath())
if err != nil {
return err
}
Expand All @@ -320,6 +320,14 @@ func (e *Env) DeployAteAPIServer(ctx context.Context) error {
return e.Kube.RolloutStatus(ctx, kube.KindDeployment, e.Namespace(), "ate-api-server", e.Cfg.RolloutTimeout)
}

// apiServerManifestPath is the ate-api-server manifest for the environment.
func (e *Env) apiServerManifestPath() string {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 nit 🟢 – DeployAtelet still inlines its kind path (e.Cfg.Path(installDir + "/kind/atelet"), deploy.go:473) while this and postgresManifestPath are helpers. An ateletManifestPath would let TestAPIServerManifestMatchesSystemBundle cover the atelet DaemonSet too, guarding the same bug class for the other single-component redeploy. Fine as a follow-up.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

if e.Cfg.Kind {
return e.Cfg.Manifest("kind", "ate-api-server")
}
return e.Cfg.Manifest("ate-api-server.yaml")
}

// DeployAteController redeploys only ate-controller.
func (e *Env) DeployAteController(ctx context.Context) error {
log.Step("deploy_ate_controller")
Expand Down Expand Up @@ -465,12 +473,7 @@ func (e *Env) DeployAtelet(ctx context.Context) error {
return err
}

path := e.Cfg.Manifest("atelet.yaml")
if e.Cfg.Kind {
// The kind overlay patches the DaemonSet for the local node layout.
path = e.Cfg.Path(installDir + "/kind/atelet")
}
manifest, err := e.render(path)
manifest, err := e.render(e.ateletManifestPath())
if err != nil {
return err
}
Expand All @@ -487,6 +490,14 @@ func (e *Env) DeployAtelet(ctx context.Context) error {
return e.waitFakeWorkersync(ctx)
}

// ateletManifestPath is the atelet manifest for the environment.
func (e *Env) ateletManifestPath() string {
if e.Cfg.Kind {
return e.Cfg.Manifest("kind", "atelet")
}
return e.Cfg.Manifest("atelet.yaml")
}

// DeployAtenet redeploys the atenet dataplane: router and egress.
func (e *Env) DeployAtenet(ctx context.Context) error {
log.Step("deploy_atenet")
Expand Down
45 changes: 45 additions & 0 deletions cmd/ate-setup/internal/steps/deploy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"path/filepath"
"testing"

"github.com/google/go-cmp/cmp"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
Expand Down Expand Up @@ -183,3 +184,47 @@ func TestMissingCRDsLeavesPresentOnesAlone(t *testing.T) {
t.Errorf("missingCRDs = %v, want only csidriverconfigs.ate.dev", names)
}
}

// A single-component redeploy has to apply what deploy ate-system does. On
// kind the bundle points the object-store plugins at rustfs, and a redeploy
// from a base file would fall back to GCS and never start.
func TestComponentManifestsMatchSystemBundle(t *testing.T) {
for _, tc := range []struct {
router string
kind bool
}{
{config.RouterEnvoy, false},
{config.RouterEnvoy, true},
{config.RouterAgentgateway, false},
{config.RouterAgentgateway, true},
} {
e := &Env{Cfg: &config.Config{Root: repoRoot(t), Router: tc.router, Kind: tc.kind}}
render := func(path string) []*unstructured.Unstructured {
manifest, err := e.render(path)
if err != nil {
t.Fatalf("render(%s): %v", path, err)
}
objs, err := kube.DecodeManifestBytes(manifest)
if err != nil {
t.Fatalf("decoding %s: %v", path, err)
}
return objs
}
bundle := render(e.Cfg.Path(SystemOverlay(e.Cfg)))
for _, component := range []struct {
kind, name, path string
}{
{"Deployment", "ate-api-server", e.apiServerManifestPath()},
{"DaemonSet", "atelet", e.ateletManifestPath()},
} {
want := findObject(bundle, component.kind, component.name)
got := findObject(render(component.path), component.kind, component.name)
if want == nil || got == nil {
t.Fatalf("router=%s kind=%v: %s/%s missing from the system bundle or %s", tc.router, tc.kind, component.kind, component.name, component.path)
}
if diff := cmp.Diff(want.Object, got.Object); diff != "" {
t.Errorf("router=%s kind=%v: %s renders a different %s/%s than the system bundle (-bundle +standalone):\n%s", tc.router, tc.kind, component.path, component.kind, component.name, diff)
}
}
}
}
8 changes: 7 additions & 1 deletion cmd/ate-setup/internal/steps/overlay_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,12 @@ func TestRenderCordonControlPlane(t *testing.T) {
path: func(e *Env) string { return e.Cfg.Manifest("ate-api-server.yaml") },
want: []string{"ate-api-server"},
},
{
name: "kind api server overlay",
cfg: config.Config{Kind: true},
path: func(e *Env) string { return e.apiServerManifestPath() },
want: []string{"ate-api-server"},
},
{
name: "podcert file",
path: func(e *Env) string { return e.Cfg.Manifest("pod-certificate-controller.yaml") },
Expand Down Expand Up @@ -629,7 +635,7 @@ func TestRenderFakeDataPlane(t *testing.T) {
{
name: "kind atelet overlay",
cfg: config.Config{Kind: true},
path: func(e *Env) string { return e.Cfg.Path(installDir + "/kind/atelet") },
path: func(e *Env) string { return e.ateletManifestPath() },
wantAtelet: true, wantStorage: "s3",
},
{
Expand Down
5 changes: 3 additions & 2 deletions docs/dev/best-practices/otel-collector.md
Original file line number Diff line number Diff line change
Expand Up @@ -428,8 +428,9 @@ the worker pods it creates, and `atenet-router`'s
`--otlp-collector-address`, which is what its Envoy is given over xDS.

Rather than editing the base manifests, prefer a kustomize overlay that
patches the variable — see `manifests/ate-install/kind/kustomization.yaml`
for a worked example.
replaces the `ate-otel-config` ConfigMap — see
`manifests/ate-install/kind/ate-otel-config.yaml`, which the kind overlay
lists instead of the base file, for a worked example.

### A Note on Logs

Expand Down
61 changes: 61 additions & 0 deletions manifests/ate-install/kind/ate-api-server/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- ../../ate-api-server.yaml

# OTEL_TRACES_SAMPLER pins ate-api-server to parentbased_always_on so every API
# call it roots is traced; the other components keep their binary defaults and
# follow its sampled flag via their ParentBased samplers. It stays an inline
# patch rather than a key in ate-otel-config.yaml because that ConfigMap is
# shared by every component via envFrom -- putting always_on there would pin the
# router and the control plane to 100% too, undoing their per-component ratios.
#
# The storage settings point ate-api-server's object-store plugin at the same
# rustfs the ../atelet overlay points atelet's at: both ends of an external
# snapshot's life have to agree on where it lives.
patches:
- patch: |-
apiVersion: apps/v1
kind: Deployment
metadata:
name: ate-api-server
namespace: ate-system
spec:
template:
spec:
containers:
- name: ate-api-server
env:
- name: OTEL_TRACES_SAMPLER
value: parentbased_always_on
initContainers:
- name: objectstore-plugin
env:
- name: ATE_STORAGE_BACKEND
value: s3
- name: AWS_REGION
value: us-east-1
- name: AWS_ENDPOINT_URL
value: http://rustfs.ate-system.svc:9000
- name: AWS_S3_USE_PATH_STYLE
value: "true"
# TODO: use a secret / identity management
- name: AWS_ACCESS_KEY_ID
value: rustfsadmin
- name: AWS_SECRET_ACCESS_KEY
value: rustfsadmin
53 changes: 5 additions & 48 deletions manifests/ate-install/kind/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,17 @@ kind: Kustomization

# ate-otel-config.yaml replaces the base ../ate-otel-config.yaml (same ConfigMap
# name) so every component's `envFrom` resolves to the in-cluster collector
# instead of the GKE one. It is listed here rather than in ./atelet because that
# overlay is also built standalone; listing it in both would be a duplicate
# resource. hack/install-ate.sh applies the ConfigMap directly for the targeted
# single-component redeploys.
# instead of the GKE one. It is listed here rather than in ./atelet or
# ./ate-api-server because those overlays are also built standalone; listing it
# in the bundle and an overlay would be a duplicate resource. ate-setup applies
# the ConfigMap directly for the single-component redeploys.
#
# pod-certificate-controller.yaml is deliberately absent, as in ../base: the
# installers (hack/install-ate.sh and cmd/ate-setup) apply and delete it on
# their own, and re-applying the base file from this bundle would revert the
# WORKERS_PER_SIGNER override.
resources:
- ../ate-api-server.yaml
- ./ate-api-server
- ../ate-controller.yaml
- ./atelet
- ../atenet-router.yaml
Expand All @@ -36,46 +36,3 @@ resources:
- rustfs.yaml
- ./otel-collector.yaml
- ./prometheus.yaml

# OTEL_TRACES_SAMPLER pins ate-api-server to parentbased_always_on so every API
# call it roots is traced; the other components keep their binary defaults and
# follow its sampled flag via their ParentBased samplers. It stays an inline
# patch rather than a key in ate-otel-config.yaml because that ConfigMap is
# shared by every component via envFrom -- putting always_on there would pin the
# router and the control plane to 100% too, undoing their per-component ratios.
#
# The storage settings point ate-api-server's object-store plugin at the same
# rustfs the ./atelet overlay points atelet's at: both ends of an external
# snapshot's life have to agree on where it lives.
patches:
- patch: |-
apiVersion: apps/v1
kind: Deployment
metadata:
name: ate-api-server
namespace: ate-system
spec:
template:
spec:
containers:
- name: ate-api-server
env:
- name: OTEL_TRACES_SAMPLER
value: parentbased_always_on
initContainers:
- name: objectstore-plugin
env:
- name: ATE_STORAGE_BACKEND
value: s3
- name: AWS_REGION
value: us-east-1
- name: AWS_ENDPOINT_URL
value: http://rustfs.ate-system.svc:9000
- name: AWS_S3_USE_PATH_STYLE
value: "true"
# TODO: use a secret / identity management
- name: AWS_ACCESS_KEY_ID
value: rustfsadmin
- name: AWS_SECRET_ACCESS_KEY
value: rustfsadmin

Loading