Skip to content

Make monitoring webhook receiver airgap-compatible: pinned image, registry resolution, node-address preference (Slice 1) - #858

Open
floatingman wants to merge 2 commits into
rancher:mainfrom
floatingman:monitoring-airgap-slice-1
Open

Make monitoring webhook receiver airgap-compatible: pinned image, registry resolution, node-address preference (Slice 1)#858
floatingman wants to merge 2 commits into
rancher:mainfrom
floatingman:monitoring-airgap-slice-1

Conversation

@floatingman

Copy link
Copy Markdown
Contributor

Closes #849

Summary

Slice 1 of the monitoring airgap PRD (#848): make the monitoring/alerting webhook-receiver validation airgap-capable by removing its unpullable dependencies on Docker Hub (traefik:latest) and public node external IPs.

Changes

New in actions/monitoring:

  • config.gomonitoringTest config section (modeled on neuvectorTest): webhookReceiverImage (pinned default traefik:v3.7.12), skipWebhookReceiver, ordered nodeAddressPreference (ExternalIP/InternalIP), with ApplyDefaults/Validate/NodeAddressTypes
  • images.goResolveImageReference(defaultRegistry, image): prefixes hostless image references with the Rancher system-default-registry setting value (Docker registry-host convention)
  • nodes.goPickNodeAddress(nodes, preference): pure resolver returning a random address for the first preference type that yields any address across nodes; errors when none match
  • Unit tests for all three (12 table-driven cases)

validation/charts/monitoring.go:

  • createAlertWebhookReceiverDeployment takes the webhook image as a parameter and resolves it against system-default-registry (empty in non-airgap → image unchanged)
  • Traefik container image: hardcoded traefik:latest → configurable, pinned by default

validation/charts/monitoring_test.go:

  • Suite loads monitoringTest config in SetupSuite (defaults + validation)
  • skipWebhookReceiver: true logs and skips only the webhook-receiver tail of TestMonitoringChart
  • External-IP-only inline node loop replaced by monitoring.PickNodeAddress honoring the configured preference

Non-airgap behavior

Unchanged: with no config and an empty system-default-registry, the deployment pulls the pinned traefik:v3.7.12 (previously floating traefik:latest), and node selection still prefers ExternalIP with InternalIP as fallback.

Verification

  • cd actions && go test ./monitoring/... -v — 12/12 pass
  • cd actions && go build ./... && go test ./... — full actions module green
  • go vet -tags validation ./validation/charts/... — clean
  • go build -tags validation ./... — whole repo builds
  • gofmt clean on all changed files
  • traefik:v3.7.12 confirmed published on Docker Hub (multi-arch, active)
  • Live TestMonitoringChart run against a Rancher + downstream cluster not executed in the development environment (no CATTLE_TEST_CONFIG); covered by the unit-test matrix above

)

- Add actions/monitoring config: pinned webhookReceiverImage default
  (traefik:v3.7.12), skipWebhookReceiver flag, ordered
  nodeAddressPreference (ExternalIP, InternalIP) with validation
- Add ResolveImageReference: prefix hostless images with the Rancher
  system-default-registry setting (empty in non-airgap, image unchanged)
- Add PickNodeAddress: pure resolver replacing the external-IP-only
  inline loop, falling back per configured preference
- Thread the configurable image through
  createAlertWebhookReceiverDeployment instead of hardcoded traefik:latest
- Load monitoringTest config in MonitoringTestSuite.SetupSuite; gate the
  webhook-receiver section on skipWebhookReceiver
@github-actions

Copy link
Copy Markdown

MonitoringTestConfig ApplyDefaults
MonitoringTestConfig Validate
MonitoringTestConfig NodeAddressTypes
MonitoringTestSuite SetupSuite
MonitoringTestSuite TestMonitoringChart
MonitoringTestSuite TestMonitoringChart
MonitoringTestSuite TestMonitoringChart
MonitoringTestSuite TestMonitoringChart
MonitoringTestSuite TestMonitoringChart
MonitoringTestSuite TestMonitoringChart
MonitoringTestSuite TestMonitoringChart
MonitoringTestSuite TestMonitoringChart
MonitoringTestSuite TestMonitoringChart

TestSuites above were modified. TestSuites below use modified code from this PR.

TestMonitoringTestConfigApplyDefaults
TestMonitoringTestConfigValidate
TestMonitoringTestConfigNodeAddressTypes
TestResolveImageReference
TestPickNodeAddress

@floatingman floatingman self-assigned this Aug 27, 2026
@floatingman floatingman added the team/pit-crew slack notifier for pit crew label Aug 27, 2026
ConfigurationFileKey = "monitoringTest"

// DefaultWebhookReceiverImage is the pinned webhook receiver image used when no override is configured. Never a floating tag.
DefaultWebhookReceiverImage = "traefik:v3.7.12"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I am wondering how much of a good idea it is to pin this version, as there may be some compatibility issues in the future plus it raises the need of one more value to maintain

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@hamistao The pin is deliberate and part of the design (#848): the floating traefik:latest tag is exactly what makes the current test non-deterministic and un-mirrorable in airgap, so the PRD specifies a pinned released version for all environments, not just airgap. Maintenance-wise, it's cheap: airgap users override it via webhookReceiverImage in the config file (no code change), and a version bump is a one-line constant. I'd also argue the compatibility risk is lower than latest, which can silently break the test at any pull.

@hamistao hamistao Sep 1, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The point is that this is a one-line constant that we will surely never again remember to update and this value will soon point to an outdated and eventually deprecated version of traefik. Then again we have so many of those at this point so what is one more. It would be nice if this lived outside the code, since it is now one more place to keep track of outdated versions (and an unusual one), but I can't think of a better suggestion than having this be the default webhookReceiverImage on our jobs' parameters, but I won't ask you to follow this unless you like the idea.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@hamistao Keeping the default in code, mainly because the external control you're describing already exists: any job or environment can set webhookReceiverImage in the config file without touching code, so only the fallback is a constant. Moving that fallback into job parameters would give us N per-job defaults that live outside version control, outside TestMonitoringTestConfigApplyDefaults, and outside repo search, with nothing to keep them in sync. On staleness, I think the failure modes favor the pin: a stale pin is a deliberate, reviewable one-line bump, while latest breaks silently at any pull and can't be mirrored into an airgap registry at all. That asymmetry is why the design (#848) pinned it.

Comment thread actions/monitoring/config.go
Comment thread actions/monitoring/config.go
Comment thread actions/monitoring/config_test.go
Comment thread validation/charts/README.md
@floatingman
floatingman requested a review from hamistao August 31, 2026 12:39
ConfigurationFileKey = "monitoringTest"

// DefaultWebhookReceiverImage is the pinned webhook receiver image used when no override is configured. Never a floating tag.
DefaultWebhookReceiverImage = "traefik:v3.7.12"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I agree, we should avoid to pin versions on the tests, could this non-deterministic behavior in airgap actually be a bug?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@lscalabrini01 Non-deterministic means that when we install only the latest, we have no control over what changes might be present in those new versions.

}

func TestPickNodeAddress(t *testing.T) {
external := corev1.NodeAddress{Type: corev1.NodeExternalIP, Address: "203.0.113.10"}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

How can we ensure the address always will be the same?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@lscalabrini01 Deterministic by construction: PickNodeAddress (nodes.go) collects addresses only for the first preference type that yields at least one match, and every table case supplies exactly one candidate for that type. So rand.IntN(len(candidates)) is always rand.IntN(1) and the exact-equal assertion holds on every run. The random pick only applies to real multi-node clusters, where any node's address serves the NodePort equally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

team/pit-crew slack notifier for pit crew

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Slice 1: Configurable pinned webhook receiver image, registry resolution, and node address resolver (monitoring airgap)

3 participants