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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ jobs:
name: e2e (${{ matrix.kube-minor }})
runs-on: ubuntu-latest
needs: [build-bink, build-operator]
timeout-minutes: 75
timeout-minutes: 105
permissions:
contents: read
strategy:
Expand Down
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ go-lines-fix: get-golines
vulncheck: govulncheck ## Check Go code for known vulnerabilities (requires network access to the Go vulnerability database).
"$(GOVULNCHECK)" ./...

# Give external-status observation room for provisioning without changing the daemon default.
E2E_BOOTC_POLL_INTERVAL ?= 10m

.PHONY: e2e
e2e: ## Run e2e tests (requires: make deploy-bink). V=1 for verbose. RUN=<regex> to filter.
# NB: we `cd` here instead of passing a package path to `go test` so that `-v`
Expand All @@ -113,6 +116,7 @@ e2e: ## Run e2e tests (requires: make deploy-bink). V=1 for verbose. RUN=<regex>
rm -rf $(ARTIFACTS)
cd test/e2e && KUBECONFIG=$(abspath $(KUBECONFIG_BINK)) \
E2E_PROVIDER=bink \
E2E_BOOTC_POLL_INTERVAL=$(E2E_BOOTC_POLL_INTERVAL) \
BINK_CLUSTER_NAME=$(BINK_CLUSTER_NAME) \
BINK_NODE_DISK_IMAGE=$(BINK_NODE_DISK_IMAGE) \
E2E_NODE_IMAGE_REGISTRY=$(BINK_LOCAL_REGISTRY_NODE_IMAGE) \
Expand Down Expand Up @@ -270,7 +274,8 @@ deploy-bink: start-bink build-update-image $(if $(RELEASED_OPERATOR_TAG),push-re
--set-string image.repository="$${img%:*}" \
--set-string image.tag="$${img##*:}" \
--set-string image.pullPolicy=Always \
--set-json 'controller.extraArgs=["--allow-insecure-registry","--tag-resolution-interval=10s"]'
--set-json 'controller.extraArgs=["--allow-insecure-registry","--tag-resolution-interval=10s"]' \
--set-string 'daemon.extraArgs[0]=--bootc-poll-interval=$(E2E_BOOTC_POLL_INTERVAL)'
kubectl --kubeconfig $(KUBECONFIG_BINK) -n bootc-operator rollout restart deployment/bootc-operator-controller
kubectl --kubeconfig $(KUBECONFIG_BINK) -n bootc-operator rollout status deployment/bootc-operator-controller --timeout=3m

Expand Down
3 changes: 3 additions & 0 deletions chart/bootc-operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ imagePullSecrets: []

controller:
extraArgs: []

daemon:
extraArgs: []
7 changes: 4 additions & 3 deletions docs/design/IMPLEMENTATION_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,10 @@ new image and the daemon reports `Idle=True`.
**Validation (e2e):** ✅ On bink, `TestExternalBootcStatusChange` runs
`bootc switch` on the host and verifies the daemon publishes the staged
image within 30 seconds of the command completing. It requires a new
status update before the first possible fallback poll, using the same
default interval as the daemon. It verifies that the BootcNode generation
stayed unchanged and the daemon pod was neither replaced nor restarted.
status update before the first possible fallback poll, using the configured
E2E interval (10 minutes by default). It verifies that the BootcNode
generation stayed unchanged and the daemon pod was neither replaced nor
restarted.

## Milestone 5: Tag Resolution & Pull Secrets

Expand Down
7 changes: 7 additions & 0 deletions hack/sync-helm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ sed -i '/^ image: {{ include "bootc-operator\.image" \. }}/i\

gen_workload "$CONFIG_DIR/daemon/daemon.yaml" DaemonSet daemon \
"$CHART_DIR/templates/daemon-daemonset.yaml"

# Inject optional daemon.extraArgs without changing the default daemon arguments.
sed -i '/^ image: {{ include "bootc-operator\.image" \. }}/i\
{{- with .Values.daemon.extraArgs }}\
args:\
{{- toYaml . | nindent 12 }}\
{{- end }}' "$CHART_DIR/templates/daemon-daemonset.yaml"
echo "Synced workloads"

# --- Bindings & ServiceAccounts ---
Expand Down
5 changes: 4 additions & 1 deletion test/e2e/upgrade_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ func helmUpgradeOperator(t *testing.T, chartPath, img string, extraArgs []string
helmRun(t, args...)
}

// helmImageArgs returns the --set flags for image and controller args.
// helmImageArgs returns the --set flags for image and E2E operator args.
// An empty img keeps the image of the chart.
func helmImageArgs(t *testing.T, img string, extraArgs []string) []string {
t.Helper()
Expand All @@ -238,6 +238,9 @@ func helmImageArgs(t *testing.T, img string, extraArgs []string) []string {
if secret := os.Getenv("E2E_IMAGE_PULL_SECRET"); secret != "" {
args = append(args, "--set", "imagePullSecrets[0].name="+secret)
}
if interval := os.Getenv("E2E_BOOTC_POLL_INTERVAL"); interval != "" {
args = append(args, "--set-string", "daemon.extraArgs[0]=--bootc-poll-interval="+interval)
}
if len(extraArgs) > 0 {
j, err := json.Marshal(extraArgs)
if err != nil {
Expand Down
16 changes: 10 additions & 6 deletions test/e2e/watcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"

bootcv1alpha1 "github.com/bootc-dev/bootc-operator/api/v1alpha1"
"github.com/bootc-dev/bootc-operator/internal/daemon"
"github.com/bootc-dev/bootc-operator/test/e2e/e2eutil"
testutil "github.com/bootc-dev/bootc-operator/test/util"
)
Expand All @@ -29,6 +28,11 @@ func TestExternalBootcStatusChange(t *testing.T) {
g := NewWithT(t)
g.SetDefaultEventuallyTimeout(pollTimeout)
g.SetDefaultEventuallyPollingInterval(pollInterval)
// Match the interval configured by deploy-bink and preserved by the upgrade test.
pollIntervalArg := os.Getenv("E2E_BOOTC_POLL_INTERVAL")
fallbackPollInterval, err := time.ParseDuration(pollIntervalArg)
g.Expect(err).NotTo(HaveOccurred(), "E2E_BOOTC_POLL_INTERVAL must be a duration")
g.Expect(fallbackPollInterval).To(BeNumerically(">", 0))
env := e2eutil.New(t)
workerCreationStart := time.Now()
nodeName := env.AddNode(t)
Expand Down Expand Up @@ -57,8 +61,8 @@ func TestExternalBootcStatusChange(t *testing.T) {
g.Expect(pod.Status.ContainerStatuses).To(ConsistOf(HaveField("RestartCount", int32(0))))
g.Expect(pod.Spec.Containers).To(HaveLen(1))
g.Expect(append(pod.Spec.Containers[0].Command, pod.Spec.Containers[0].Args...)).
NotTo(ContainElement(ContainSubstring("bootc-poll-interval")),
"the test relies on the daemon's default polling interval")
To(ContainElement("--bootc-poll-interval="+pollIntervalArg),
"the test relies on the configured E2E polling interval")

const stageUnit = "bootc-e2e-external-switch.service"
// Killing kubectl does not stop a transient service on the host. Run this
Expand Down Expand Up @@ -101,7 +105,7 @@ func TestExternalBootcStatusChange(t *testing.T) {
"bootc", "switch", env.NodeImageUpdateDigestedPullSpec(),
)

// This is well below the daemon's default fallback polling interval.
// This is well below the configured E2E fallback polling interval.
observationCtx, cancelObservation := context.WithTimeout(ctx, 30*time.Second)
defer cancelObservation()
testutil.WaitForNodeIdle(t, g, observationCtx, env.Client, nodeName, 30*time.Second,
Expand All @@ -111,10 +115,10 @@ func TestExternalBootcStatusChange(t *testing.T) {
g.Expect(observationCtx.Err()).
NotTo(HaveOccurred(), "status must be observed within 30 seconds")

// Fallback polling waits for the default interval after watcher startup.
// Fallback polling waits for the configured interval after watcher startup.
// This bound starts before the worker exists and uses the runner's clock,
// so a fallback poll cannot account for the observed status update.
g.Expect(time.Since(workerCreationStart)).To(BeNumerically("<", daemon.DefaultPollInterval),
g.Expect(time.Since(workerCreationStart)).To(BeNumerically("<", fallbackPollInterval),
"status must be observed before the first possible fallback poll")

var after bootcv1alpha1.BootcNode
Expand Down
Loading