feat(providerconfig): add stackSecretRef to consume stack connection secrets#518
feat(providerconfig): add stackSecretRef to consume stack connection secrets#518
Conversation
e5ca380 to
f3ec8de
Compare
Add an optional ConnectionDetailsFn field to the tfdatasource.Spec that allows observed resources to publish connection details to a Secret via writeConnectionSecretToRef. The function is called in both Observe (when up-to-date) and Update (after a successful read). Extend the generate-observed emitter to automatically generate a ConnectionDetailsFn for every observed resource that has scalar atProvider fields. Each field is exported using its Terraform attribute name as the secret key.
Add AdditionalConnectionDetailsFn to the grafana_cloud_stack resource configurator. All scalar atProvider fields (URLs, names, statuses, IDs) are exported as individual keys in the connection secret using their Terraform attribute names.
Add an optional StackSecretRef field to all ProviderConfigSpec types (cluster, namespaced, and cluster-namespaced). When set, the referenced Secret is fetched and its keys are merged into the credential map with key remapping (oncall_api_url -> oncall_url, id -> stack_id). Precedence (lowest to highest): 1. Primary credential secret (credentials.secretRef) 2. Stack secret (stackSecretRef) 3. ProviderConfig spec fields (url, oncallUrl, etc.)
Add documentation for the new stackSecretRef field on ProviderConfig, including how Stack connection secrets are produced, key remapping (oncall_api_url -> oncall_url, id -> stack_id), precedence order, and a complete example showing the Stack -> Secret -> ProviderConfig chain.
f3ec8de to
55beff1
Compare
Replace GRAFANA_URL and GRAFANA_ONCALL_URL env vars with GRAFANA_CLOUD_ACCESS_POLICY_TOKEN and GRAFANA_STACK_SLUG. The setup script now observes the existing stack via a data source, publishes its connection details to a Secret, and wires both ProviderConfigs with stackSecretRef. This lets all cloud e2e tests (including oncall) resolve urls automatically from the stack secret instead of hardcoded env vars. The new stack-secret-ref.yaml test creates a Folder using an auth-only credential secret, proving the url comes exclusively from stackSecretRef.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9f4fa22330
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| ConnectionDetailsFn: func(mg resource.Managed) managed.ConnectionDetails { | ||
| cr := mg.(*v1alpha1.Stack) | ||
| cd := managed.ConnectionDetails{} | ||
| if cr.Status.AtProvider.AlertmanagerIPAllowListCname != nil { |
There was a problem hiding this comment.
Include datasource id in observed Stack connection details
This connection-details closure never emits an id key, so stackSecretRef cannot populate stack_id when the secret comes from an observed cloud.grafana.o Stack. The read path stores datasource id only as external name (meta.SetExternalName(cr, d.Id())), and mergeStackSecret() relies on an id -> stack_id remap, so any ProviderConfig that depends on observed-stack secrets for stack_id (for example k6/cloud-provider flows) will still fail unless users manually set spec.stackId.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in bd45734: the generator now emits the external name as id in all observed ConnectionDetailsFn closures.
See lines 414-416:
if id := meta.GetExternalName(cr); id != "" {
cd["id"] = []byte(id)
}The ConnectionDetailsFn for observed resources only emitted atProvider fields but not the datasource id which is stored as external name. This meant stackSecretRef could not populate stack_id from an observed Stack connection secret. Now all observed resources emit the external name as the 'id' key in their connection details.
Summary
Allow
ProviderConfigresources to reference a connection secret produced by agrafana_cloud_stackresource (managed or observed) via a newstackSecretReffield. This automatically populates URL and ID credential fields, eliminating manual configuration of stack-specific endpoints.Stack secret coverage of ProviderConfig fields
stackSecretRef?spec.urlspec.oncallUrloncall_api_urlspec.fleetManagementUrlspec.orgIdspec.stackIdidspec.smUrlspec.cloudApiUrlspec.cloudProviderUrlspec.connectionsApiUrl5 of 9 ProviderConfig spec fields are covered. The remaining 4 are not stack attributes — they are either environment-specific URLs or not yet exposed by the upstream TF provider.
Key changes:
ConnectionDetailsFn, enabling them to publish connection details to a secretgrafana_cloud_stackresource exports all scalaratProviderfields as connection detail keysstackSecretRefthat reads the stack secret and merges it into the credential map with key remapping (oncall_api_url→oncall_url,id→stack_id)Precedence (lowest → highest)
credentials.secretRef)stackSecretRef)url,oncallUrl, etc.)Review Guide
Hand-edited files
config/grafana/cloud.goAdditionalConnectionDetailsFntografana_cloud_stack, exporting all scalar TF state attributesdocs/providerconfig-secret-fields.mdstackSecretRef, key remapping, precedence, coverage tablepkg/generateobserved/emit.goConnectionDetailsFnfor all observed resources with scalaratProviderfields; includes external name asidinternal/clients/grafana.gomergeStackSecret()helper, key remap map, wired intoTerraformSetupBuilder()andExtractModernConfig()pkg/tfdatasource/controller.goConnectionDetailsFnfield toSpec, wired intoObserve()andUpdate()apis/cluster/v1beta1/types.goStackSecretRef *xpv1.SecretReferencetoProviderConfigSpecapis/namespaced/v1beta1/types.goStackSecretRef *xpv1.SecretReferencetoProviderConfigSpeccluster/test/setup-cloud.shstackSecretRefinstead of hardcoded URLscluster/test/teardown-cloud.shMakefileGRAFANA_URL/GRAFANA_ONCALL_URLwithGRAFANA_CLOUD_ACCESS_POLICY_TOKEN/GRAFANA_STACK_SLUGexamples/cloud/v1alpha1/stack-secret-ref.yamlstackSecretRefGenerated files
Everything else in the diff is generated output from
make generate:internal/controller/namespaced/observed/*/zz_*_spec.go— All observed specs now includeConnectionDetailsFnwith external name asidapis/*/zz_generated.deepcopy.go— Updated forStackSecretRefpackage/crds/*.yaml— CRDs updated withstackSecretRefapis/*/enterprise/v1alpha1/zz_*.go,apis/*/oss/v1alpha1/zz_*.go,config/provider-metadata.yaml— Upstream v4.29.0 schema changes (unrelated to this PR)examples-generated/*/oss/v1alpha1/dashboardv2.yaml— Removed by upstream v4.29.0 changesUsage Examples
Managed Stack → ProviderConfig
The ProviderConfig automatically gets
url,oncall_url,fleet_management_url,org_id,stack_id, and all other stack fields — no manual endpoint configuration needed.Observed (data-source) Stack → ProviderConfig
For pre-existing stacks not managed by Crossplane:
Overriding specific fields
Stack secret values can be selectively overridden via ProviderConfig spec fields:
E2E Test
The
stackSecretReffeature is tested end-to-end in thee2e-cloudsuite (make e2e-cloud).How it works
The cloud e2e setup (
cluster/test/setup-cloud.sh) now:ClusterProviderConfigusingGRAFANA_CLOUD_ACCESS_POLICY_TOKENcloud.grafana.o.crossplane.io/v1alpha1 Stack) byGRAFANA_STACK_SLUGatProviderfields (url, oncall_api_url, org_id, etc.) to a connection Secret viawriteConnectionSecretToRef{"auth": "..."}— intentionally no URL)ProviderConfigandClusterProviderConfignamede2e-cloud-instancewith:credentials.secretRef→ auth-only secretstackSecretRef→ observed stack's connection secretWhat it proves
stack-secret-ref.yaml: Creates a Folder usinge2e-cloud-instance. Since the auth secret has no URL, the Folder can only be created ifstackSecretRefcorrectly provides theurlfrom the observed Stack's connection secret.oncall-escalation-refs.yamlandoncall-shift-rolling-users.yaml: These existing oncall tests now getoncall_urlfrom the stack secret (remapped fromoncall_api_url) instead of a hardcodedGRAFANA_ONCALL_URLenv var.Required env vars
Running