Skip to content

feat: instantiate policyRefs remoteURL.url as a template per cluster - #2001

Merged
gianlucam76 merged 1 commit into
projectsveltos:mainfrom
monadic:templated-remoteurl
Sep 28, 2026
Merged

gianlucam76 merged 1 commit into
projectsveltos:mainfrom
monadic:templated-remoteurl

Conversation

@monadic

@monadic monadic commented Sep 27, 2026

Copy link
Copy Markdown
Contributor

Gianluca is this ok? alexis

What

spec.policyRefs[].remoteURL.url can now be a template, instantiated for each
matching cluster before Sveltos fetches it. This works the same way as
remoteURL.secretRef.name/namespace and ConfigMap/Secret policyRef names,
with the same template data (.Cluster, .ClusterNamespace, .ClusterName) and
the same functions. One ClusterProfile can then pull a different artifact for
each cluster:

policyRefs:
- deploymentType: Remote
  remoteURL:
    url: "oci://registry.example/space/kyverno-{{ .Cluster.metadata.name }}:latest"

Why

Today the URL is used as written. A templated URL fails with
failed to parse OCI reference ...: invalid reference, so per-cluster
content needs one ClusterProfile per cluster, even though the secretRef
next to the URL is already templated.

How

  • controllers/url_source.go: new instantiateRemoteURL helper. It returns a URL
    without {{ unchanged and does not read the Cluster. Otherwise it renders
    the URL with text/template, using the data libsveltos uses for reference
    names and missingkey=error. It uses text/template, not the html/template-based
    libsveltos helper, because html/template HTML-escapes values that come from
    cluster fields. For example, + becomes + and & becomes &,
    which would corrupt a URL.
  • deployContentOfURL instantiates the URL before fetching, for both OCI and
    HTTP(S). A failure is returned as TemplateInstantiationError (reported as
    FailedNonRetriable), even when the ref is optional. This matches how
    ConfigMap/Secret names behave. The deployed resources' reference-name
    annotation records the instantiated URL.
  • urlPolicyRefsHash instantiates the URL before fetching it for the hash, so
    content changes are detected for each cluster. A template error is logged
    and skipped there, as getInstantiatedPolicyRefInfo already does for
    ConfigMap/Secret names. The deploy step reports the error.
  • api/v1beta1/spec.go: the RemoteURL.URL doc now says it can be a template.
    CRDs, lib/crd and manifest/manifest.yaml were regenerated (description only).

KustomizationRef.remoteURL is unchanged. The same helper could be applied
there in a follow-up.

Tests

  • controllers/url_source_test.go, new "RemoteURL templating" specs (envtest
    Cluster plus an in-process OCI registry and httptest server):
    • templated OCI URL: instantiated to the cluster's repository, and
      urlPolicyRefsHash fetches that artifact
    • templated HTTP URL with a label, an annotation containing '+', and '&'
      in the query: the URL is fetched without HTML escaping (this spec fails
      if the html/template helper is used instead)
    • URL without a template: returned unchanged, with no Cluster lookup
    • missing key: instantiateRemoteURL returns an error, deployContentOfURL
      returns TemplateInstantiationError (optional ref too), and the hash skips
      the ref
  • make test and make lint pass (0 issues), on main at be25edd.
  • Manual check on kind with Sveltos v1.15.0 and this image: a ClusterProfile
    with url oci://<registry>/space/demo-{{ .Cluster.metadata.name }}:latest
    deployed the demo-w1 artifact to cluster w1 (Provisioned). Pushing new
    content to demo-w1 was redeployed within the 1m interval. A URL using a
    missing label reported FailedNonRetriable with the template error. Stock
    v1.15.0 reports Failed with invalid reference for the same profile.

🤖 Generated with Claude Code

spec.policyRefs[].remoteURL.url can now be a template, instantiated for
each matching cluster before Sveltos fetches it, the same way
remoteURL.secretRef and ConfigMap/Secret policyRef names already are. One
ClusterProfile can then pull a different artifact for each cluster.

It uses text/template rather than the html/template-based helper, so
values taken from cluster fields are not HTML-escaped into the URL.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@gianlucam76 gianlucam76 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you @monadic. This is great.

We can avoid some duplication by exporting a method in libsveltos. But that is not a problem with this PR. It is something already existing that I will handle in separate PRs.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants