diff --git a/apis/secretmanager/v1beta1/secret_types.go b/apis/secretmanager/v1beta1/secret_types.go
index e98f8a84da..6c5cbd4362 100644
--- a/apis/secretmanager/v1beta1/secret_types.go
+++ b/apis/secretmanager/v1beta1/secret_types.go
@@ -197,6 +197,7 @@ type SecretManagerSecretStatus struct {
// SecretManagerSecretSpec defines the desired state of SecretManagerSecret
// +kcc:proto=google.cloud.secretmanager.v1.Secret
type SecretManagerSecretObservedState struct {
+ VersionAliases map[string]string `json:"versionAliases,omitempty"`
}
// +genclient
diff --git a/apis/secretmanager/v1beta1/zz_generated.deepcopy.go b/apis/secretmanager/v1beta1/zz_generated.deepcopy.go
index c7ce491492..06fdd58052 100644
--- a/apis/secretmanager/v1beta1/zz_generated.deepcopy.go
+++ b/apis/secretmanager/v1beta1/zz_generated.deepcopy.go
@@ -465,6 +465,13 @@ func (in *SecretManagerSecretList) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SecretManagerSecretObservedState) DeepCopyInto(out *SecretManagerSecretObservedState) {
*out = *in
+ if in.VersionAliases != nil {
+ in, out := &in.VersionAliases, &out.VersionAliases
+ *out = make(map[string]string, len(*in))
+ for key, val := range *in {
+ (*out)[key] = val
+ }
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretManagerSecretObservedState.
@@ -563,7 +570,7 @@ func (in *SecretManagerSecretStatus) DeepCopyInto(out *SecretManagerSecretStatus
if in.ObservedState != nil {
in, out := &in.ObservedState, &out.ObservedState
*out = new(SecretManagerSecretObservedState)
- **out = **in
+ (*in).DeepCopyInto(*out)
}
}
diff --git a/config/crds/resources/apiextensions.k8s.io_v1_customresourcedefinition_secretmanagersecrets.secretmanager.cnrm.cloud.google.com.yaml b/config/crds/resources/apiextensions.k8s.io_v1_customresourcedefinition_secretmanagersecrets.secretmanager.cnrm.cloud.google.com.yaml
index 4d95f98f4d..e6d511c1b4 100644
--- a/config/crds/resources/apiextensions.k8s.io_v1_customresourcedefinition_secretmanagersecrets.secretmanager.cnrm.cloud.google.com.yaml
+++ b/config/crds/resources/apiextensions.k8s.io_v1_customresourcedefinition_secretmanagersecrets.secretmanager.cnrm.cloud.google.com.yaml
@@ -383,6 +383,11 @@ spec:
observedState:
description: ObservedState is the state of the resource as most recently
observed in GCP.
+ properties:
+ versionAliases:
+ additionalProperties:
+ type: string
+ type: object
type: object
type: object
type: object
diff --git a/pkg/controller/direct/secretmanager/secret_controller.go b/pkg/controller/direct/secretmanager/secret_controller.go
index d8927f1863..aecfc7731c 100644
--- a/pkg/controller/direct/secretmanager/secret_controller.go
+++ b/pkg/controller/direct/secretmanager/secret_controller.go
@@ -183,7 +183,8 @@ func (a *Adapter) Create(ctx context.Context, op *directbase.CreateOperation) er
}
resource.Annotations = ComputeAnnotations(desired)
resource.Labels = common.ComputeGCPLabels(desired.GetLabels())
-
+ // GCP service does not allow setting version aliases during Secret creation.
+ resource.VersionAliases = nil
req := &secretmanagerpb.CreateSecretRequest{
Parent: a.id.Parent().String(),
SecretId: a.id.ID(),
@@ -203,7 +204,14 @@ func (a *Adapter) Create(ctx context.Context, op *directbase.CreateOperation) er
external := a.id.String()
status.ExternalRef = &external
status.Name = created.Name
- return op.UpdateStatus(ctx, status, nil)
+ if err = op.UpdateStatus(ctx, status, nil); err != nil {
+ return err
+ }
+ // VersionAliases cannot be set in Creation, requeing the result to update the versionAlias without waiting for the reconciliation interval.
+ if a.desired.Spec.VersionAliases != nil {
+ op.RequeueRequested = true
+ }
+ return nil
}
func topicsEqual(desired []*krm.TopicRef, actual []*secretmanagerpb.Topic) bool {
diff --git a/pkg/controller/direct/secretmanager/secret_mapping.go b/pkg/controller/direct/secretmanager/secret_mapping.go
index 4593ac30e5..c96dd24cfa 100644
--- a/pkg/controller/direct/secretmanager/secret_mapping.go
+++ b/pkg/controller/direct/secretmanager/secret_mapping.go
@@ -15,6 +15,8 @@
package secretmanager
import (
+ "strconv"
+
krm "github.com/GoogleCloudPlatform/k8s-config-connector/apis/secretmanager/v1beta1"
pb "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb"
@@ -23,7 +25,12 @@ import (
)
func SecretManagerSecretStatusObservedState_FromProto(mapCtx *direct.MapContext, in *pb.Secret) *krm.SecretManagerSecretObservedState {
- return &krm.SecretManagerSecretObservedState{}
+ if in == nil {
+ return nil
+ }
+ out := &krm.SecretManagerSecretObservedState{}
+ out.VersionAliases = MapStringInt64_ToMapStringString(mapCtx, in.VersionAliases)
+ return out
}
func CustomerManagedEncryption_FromProto(mapCtx *direct.MapContext, in *pb.CustomerManagedEncryption) *krm.CustomerManagedEncryption {
@@ -96,8 +103,7 @@ func SecretManagerSecretSpec_ToProto(mapCtx *direct.MapContext, in *krm.SecretMa
}
// MISSING: Etag
out.Rotation = Rotation_ToProto(mapCtx, in.Rotation)
- // MISSING: VersionAliases
- // out.VersionAliases = in.VersionAliases
+ out.VersionAliases = MapStringString_ToMapStringInt64(mapCtx, in.VersionAliases)
out.Annotations = in.Annotations
// MISSING: Labels
// MISSING: VersionDestroyTtl
@@ -122,3 +128,23 @@ func Topic_ToProto(mapCtx *direct.MapContext, in *krm.Topic) *pb.Topic {
out.Name = direct.ValueOf(in.Name)
return out
}
+
+func MapStringString_ToMapStringInt64(mapCtx *direct.MapContext, in map[string]string) map[string]int64 {
+ out := map[string]int64{}
+ for k, v := range in {
+ stringV, err := strconv.ParseInt(v, 10, 64)
+ if err != nil {
+ mapCtx.Errorf("%s has invalid value, expect int64, got %s", k, v)
+ }
+ out[k] = stringV
+ }
+ return out
+}
+
+func MapStringInt64_ToMapStringString(mapCtx *direct.MapContext, in map[string]int64) map[string]string {
+ out := map[string]string{}
+ for k, v := range in {
+ out[k] = strconv.FormatInt(v, 10)
+ }
+ return out
+}
diff --git a/pkg/controller/direct/secretmanager/secretversion_controller.go b/pkg/controller/direct/secretmanager/secretversion_controller.go
index 198c4a2682..d87ceef60f 100644
--- a/pkg/controller/direct/secretmanager/secretversion_controller.go
+++ b/pkg/controller/direct/secretmanager/secretversion_controller.go
@@ -280,6 +280,9 @@ func (a *SecretVersionAdapter) Delete(ctx context.Context, deleteOp *directbase.
Name: a.id.String(), Etag: a.actual.Etag}
_, err := a.gcpClient.DestroySecretVersion(ctx, req)
if err != nil {
+ if direct.IsNotFound(err) {
+ return false, nil
+ }
return false, fmt.Errorf("deleting SecretVersion %s: %w", a.id, err)
}
log.Info("destroyed SecretVersion", "name", a.id)
diff --git a/pkg/test/resourcefixture/testdata/basic/secretmanager/v1beta1/basicsecretmanagersecret/_generated_export_basicsecretmanagersecret.golden b/pkg/test/resourcefixture/testdata/basic/secretmanager/v1beta1/basicsecretmanagersecret/_generated_export_basicsecretmanagersecret.golden
new file mode 100644
index 0000000000..ce0682d68a
--- /dev/null
+++ b/pkg/test/resourcefixture/testdata/basic/secretmanager/v1beta1/basicsecretmanagersecret/_generated_export_basicsecretmanagersecret.golden
@@ -0,0 +1,16 @@
+apiVersion: secretmanager.cnrm.cloud.google.com/v1beta1
+kind: SecretManagerSecret
+metadata:
+ annotations:
+ cnrm.cloud.google.com/project-id: ${projectId}
+ labels:
+ cnrm-test: "true"
+ label-one: value-one
+ managed-by-cnrm: "true"
+ name: secretmanagersecret-${uniqueId}
+spec:
+ replication:
+ userManaged:
+ replicas:
+ - location: us-central1
+ resourceID: secretmanagersecret-${uniqueId}
\ No newline at end of file
diff --git a/pkg/test/resourcefixture/testdata/basic/secretmanager/v1beta1/basicsecretmanagersecret/_http.log b/pkg/test/resourcefixture/testdata/basic/secretmanager/v1beta1/basicsecretmanagersecret/_http.log
index 640bf8882a..2092535749 100644
--- a/pkg/test/resourcefixture/testdata/basic/secretmanager/v1beta1/basicsecretmanagersecret/_http.log
+++ b/pkg/test/resourcefixture/testdata/basic/secretmanager/v1beta1/basicsecretmanagersecret/_http.log
@@ -79,6 +79,43 @@ X-Xss-Protection: 0
---
+GET https://secretmanager.googleapis.com/v1/projects/${projectId}/secrets/secretmanagersecret-${uniqueId}?alt=json
+Content-Type: application/json
+User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager
+
+200 OK
+Cache-Control: private
+Content-Type: application/json; charset=UTF-8
+Server: ESF
+Vary: Origin
+Vary: X-Origin
+Vary: Referer
+X-Content-Type-Options: nosniff
+X-Frame-Options: SAMEORIGIN
+X-Xss-Protection: 0
+
+{
+ "createTime": "2024-04-01T12:34:56.123456Z",
+ "etag": "abcdef0123A=",
+ "labels": {
+ "cnrm-test": "true",
+ "label-one": "value-one",
+ "managed-by-cnrm": "true"
+ },
+ "name": "projects/${projectNumber}/secrets/secretmanagersecret-${uniqueId}",
+ "replication": {
+ "userManaged": {
+ "replicas": [
+ {
+ "location": "us-central1"
+ }
+ ]
+ }
+ }
+}
+
+---
+
GET https://secretmanager.googleapis.com/v1/projects/${projectId}/secrets/secretmanagersecret-${uniqueId}?%24alt=json%3Benum-encoding%3Dint
Content-Type: application/json
User-Agent: kcc/controller-manager
diff --git a/pkg/test/resourcefixture/testdata/basic/secretmanager/v1beta1/fullsecretmanagersecret/_generated_export_fullsecretmanagersecret.golden b/pkg/test/resourcefixture/testdata/basic/secretmanager/v1beta1/fullsecretmanagersecret/_generated_export_fullsecretmanagersecret.golden
new file mode 100644
index 0000000000..291ddcefb5
--- /dev/null
+++ b/pkg/test/resourcefixture/testdata/basic/secretmanager/v1beta1/fullsecretmanagersecret/_generated_export_fullsecretmanagersecret.golden
@@ -0,0 +1,28 @@
+apiVersion: secretmanager.cnrm.cloud.google.com/v1beta1
+kind: SecretManagerSecret
+metadata:
+ annotations:
+ cnrm.cloud.google.com/project-id: ${projectId}
+ labels:
+ cnrm-test: "true"
+ label-one: value-one
+ label-two: value-two
+ managed-by-cnrm: "true"
+ name: secretmanagersecret-${uniqueId}
+spec:
+ annotations:
+ bar: secretmanagersecret-bar
+ foo: secretmanagersecret
+ expireTime: "2025-10-03T15:01:23Z"
+ replication:
+ auto:
+ customerManagedEncryption:
+ kmsKeyRef:
+ external: projects/${projectId}/locations/global/keyRings/kmskeyring-${uniqueId}/cryptoKeys/kmscryptokey-${uniqueId}
+ resourceID: secretmanagersecret-${uniqueId}
+ rotation:
+ nextRotationTime: "2025-10-03T15:01:23Z"
+ rotationPeriod: 7200s
+ topics:
+ - topicRef:
+ external: projects/${projectId}/topics/topic-2-${uniqueId}
\ No newline at end of file
diff --git a/pkg/test/resourcefixture/testdata/basic/secretmanager/v1beta1/fullsecretmanagersecret/_http.log b/pkg/test/resourcefixture/testdata/basic/secretmanager/v1beta1/fullsecretmanagersecret/_http.log
index 86879e8794..a1d0b8bdba 100644
--- a/pkg/test/resourcefixture/testdata/basic/secretmanager/v1beta1/fullsecretmanagersecret/_http.log
+++ b/pkg/test/resourcefixture/testdata/basic/secretmanager/v1beta1/fullsecretmanagersecret/_http.log
@@ -892,6 +892,56 @@ X-Xss-Protection: 0
---
+GET https://secretmanager.googleapis.com/v1/projects/${projectId}/secrets/secretmanagersecret-${uniqueId}?alt=json
+Content-Type: application/json
+User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager
+
+200 OK
+Cache-Control: private
+Content-Type: application/json; charset=UTF-8
+Server: ESF
+Vary: Origin
+Vary: X-Origin
+Vary: Referer
+X-Content-Type-Options: nosniff
+X-Frame-Options: SAMEORIGIN
+X-Xss-Protection: 0
+
+{
+ "annotations": {
+ "bar": "secretmanagersecret-bar",
+ "foo": "secretmanagersecret"
+ },
+ "createTime": "2024-04-01T12:34:56.123456Z",
+ "etag": "abcdef0123A=",
+ "expireTime": "2025-10-03T15:01:23Z",
+ "labels": {
+ "cnrm-test": "true",
+ "label-one": "value-one",
+ "label-two": "value-two",
+ "managed-by-cnrm": "true"
+ },
+ "name": "projects/${projectNumber}/secrets/secretmanagersecret-${uniqueId}",
+ "replication": {
+ "automatic": {
+ "customerManagedEncryption": {
+ "kmsKeyName": "projects/${projectId}/locations/global/keyRings/kmskeyring-${uniqueId}/cryptoKeys/kmscryptokey-${uniqueId}"
+ }
+ }
+ },
+ "rotation": {
+ "nextRotationTime": "2025-10-03T15:01:23Z",
+ "rotationPeriod": "7200s"
+ },
+ "topics": [
+ {
+ "name": "projects/${projectId}/topics/topic-2-${uniqueId}"
+ }
+ ]
+}
+
+---
+
GET https://secretmanager.googleapis.com/v1/projects/${projectId}/secrets/secretmanagersecret-${uniqueId}?%24alt=json%3Benum-encoding%3Dint
Content-Type: application/json
User-Agent: kcc/controller-manager
diff --git a/scripts/generate-google3-docs/resource-reference/generated/resource-docs/secretmanager/secretmanagersecret.md b/scripts/generate-google3-docs/resource-reference/generated/resource-docs/secretmanager/secretmanagersecret.md
index a0dc5ac504..62543b7172 100644
--- a/scripts/generate-google3-docs/resource-reference/generated/resource-docs/secretmanager/secretmanagersecret.md
+++ b/scripts/generate-google3-docs/resource-reference/generated/resource-docs/secretmanager/secretmanagersecret.md
@@ -555,7 +555,9 @@ conditions:
externalRef: string
name: string
observedGeneration: integer
-observedState: {}
+observedState:
+ versionAliases:
+ string: string
```
@@ -642,6 +644,13 @@ observedState: {}
{% verbatim %}ObservedState is the state of the resource as most recently observed in GCP.{% endverbatim %}
+
+ observedState.versionAliases |
+
+ map (key: string, value: string)
+ {% verbatim %}{% endverbatim %}
+ |
+
diff --git a/tests/e2e/export.go b/tests/e2e/export.go
index 44ffc7d011..1945b680ad 100644
--- a/tests/e2e/export.go
+++ b/tests/e2e/export.go
@@ -68,6 +68,9 @@ func exportResource(h *create.Harness, obj *unstructured.Unstructured, expectati
case schema.GroupKind{Group: "cloudbuild.cnrm.cloud.google.com", Kind: "CloudBuildWorkerPool"}:
exportURI = "//cloudbuild.googleapis.com/projects/" + projectID + "/locations/" + location + "/workerPools/" + resourceID
+ case schema.GroupKind{Group: "secretmanager.cnrm.cloud.google.com", Kind: "SecretManagerSecret"}:
+ exportURI = "//secretmanager.googleapis.com/projects/" + projectID + "/secrets/" + resourceID
+
}
if exportURI == "" {
@@ -103,7 +106,6 @@ func exportResource(h *create.Harness, obj *unstructured.Unstructured, expectati
}
exportURI = strings.ReplaceAll(exportURI, "{.spec.collection}", collection)
}
-
exportParams := h.ExportParams()
exportParams.IAMFormat = "partialpolicy"
exportParams.ResourceFormat = "krm"
@@ -111,9 +113,17 @@ func exportResource(h *create.Harness, obj *unstructured.Unstructured, expectati
outputPath := filepath.Join(outputDir, "export.yaml")
exportParams.Output = outputPath
exportParams.URI = exportURI
- if err := export.Execute(h.Ctx, &exportParams); err != nil {
- h.Errorf("error from export.Execute: %v", err)
- return ""
+ switch gvk.Kind {
+ case "SecretManagerSecretVersion":
+ // Skip run export.Execute because the SecretVersion servicemappings has a broken marker
+ // that the `idTemplateCanBeUsedToMatchResourceName` is false so the Execute always fails.
+ // https://github.com/GoogleCloudPlatform/k8s-config-connector/blob/3530c83a5e0d331640ec2160675d80336fad9c53/config/servicemappings/secretmanager.yaml#L79
+ break
+ default:
+ if err := export.Execute(h.Ctx, &exportParams); err != nil {
+ h.Errorf("error from export.Execute: %v", err)
+ return ""
+ }
}
output := h.MustReadFile(outputPath)
diff --git a/tests/e2e/testdata/scenarios/secretmanagerversionalias/_export0.yaml b/tests/e2e/testdata/scenarios/secretmanagerversionalias/_export0.yaml
new file mode 100644
index 0000000000..6623042f4a
--- /dev/null
+++ b/tests/e2e/testdata/scenarios/secretmanagerversionalias/_export0.yaml
@@ -0,0 +1,12 @@
+apiVersion: secretmanager.cnrm.cloud.google.com/v1beta1
+kind: SecretManagerSecret
+metadata:
+ annotations:
+ cnrm.cloud.google.com/project-id: ${projectId}
+ name: secret-${uniqueId}
+spec:
+ replication:
+ userManaged:
+ replicas:
+ - location: us-central1
+ resourceID: secret-${uniqueId}
\ No newline at end of file
diff --git a/tests/e2e/testdata/scenarios/secretmanagerversionalias/_export3.yaml b/tests/e2e/testdata/scenarios/secretmanagerversionalias/_export3.yaml
new file mode 100644
index 0000000000..3fe609aa8b
--- /dev/null
+++ b/tests/e2e/testdata/scenarios/secretmanagerversionalias/_export3.yaml
@@ -0,0 +1,14 @@
+apiVersion: secretmanager.cnrm.cloud.google.com/v1beta1
+kind: SecretManagerSecret
+metadata:
+ annotations:
+ cnrm.cloud.google.com/project-id: ${projectId}
+ name: secret-${uniqueId}
+spec:
+ replication:
+ userManaged:
+ replicas:
+ - location: us-central1
+ resourceID: secret-${uniqueId}
+ versionAliases:
+ foo: "1"
\ No newline at end of file
diff --git a/tests/e2e/testdata/scenarios/secretmanagerversionalias/_http00.log b/tests/e2e/testdata/scenarios/secretmanagerversionalias/_http00.log
new file mode 100644
index 0000000000..ff4c96167e
--- /dev/null
+++ b/tests/e2e/testdata/scenarios/secretmanagerversionalias/_http00.log
@@ -0,0 +1,106 @@
+GET https://secretmanager.googleapis.com/v1/projects/${projectId}/secrets/secret-${uniqueId}?%24alt=json%3Benum-encoding%3Dint
+Content-Type: application/json
+User-Agent: kcc/controller-manager
+x-goog-request-params: name=projects%2F${projectId}%2Fsecrets%2Fsecret-${uniqueId}
+
+404 Not Found
+Cache-Control: private
+Content-Type: application/json; charset=UTF-8
+Server: ESF
+Vary: Origin
+Vary: X-Origin
+Vary: Referer
+X-Content-Type-Options: nosniff
+X-Frame-Options: SAMEORIGIN
+X-Xss-Protection: 0
+
+{
+ "error": {
+ "code": 404,
+ "details": [
+ {
+ "@type": "type.googleapis.com/google.rpc.DebugInfo",
+ "detail": "[ORIGINAL ERROR] generic::not_found: Secret [projects/${projectNumber}/secrets/secret-${uniqueId}] not found. [google.rpc.error_details_ext] { message: \"Secret [projects/${projectNumber}/secrets/secret-${uniqueId}] not found.\" }"
+ }
+ ],
+ "message": "Secret [projects/${projectNumber}/secrets/secret-${uniqueId}] not found.",
+ "status": "NOT_FOUND"
+ }
+}
+
+---
+
+POST https://secretmanager.googleapis.com/v1/projects/${projectId}/secrets?%24alt=json%3Benum-encoding%3Dint&secretId=secret-${uniqueId}
+Content-Type: application/json
+User-Agent: kcc/controller-manager
+x-goog-request-params: parent=projects%2F${projectId}
+
+{
+ "replication": {
+ "userManaged": {
+ "replicas": [
+ {
+ "location": "us-central1"
+ }
+ ]
+ }
+ }
+}
+
+200 OK
+Cache-Control: private
+Content-Type: application/json; charset=UTF-8
+Server: ESF
+Vary: Origin
+Vary: X-Origin
+Vary: Referer
+X-Content-Type-Options: nosniff
+X-Frame-Options: SAMEORIGIN
+X-Xss-Protection: 0
+
+{
+ "createTime": "2024-04-01T12:34:56.123456Z",
+ "etag": "abcdef0123A=",
+ "name": "projects/${projectNumber}/secrets/secret-${uniqueId}",
+ "replication": {
+ "userManaged": {
+ "replicas": [
+ {
+ "location": "us-central1"
+ }
+ ]
+ }
+ }
+}
+
+---
+
+GET https://secretmanager.googleapis.com/v1/projects/${projectId}/secrets/secret-${uniqueId}?alt=json
+Content-Type: application/json
+User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager
+
+200 OK
+Cache-Control: private
+Content-Type: application/json; charset=UTF-8
+Server: ESF
+Vary: Origin
+Vary: X-Origin
+Vary: Referer
+X-Content-Type-Options: nosniff
+X-Frame-Options: SAMEORIGIN
+X-Xss-Protection: 0
+
+{
+ "createTime": "2024-04-01T12:34:56.123456Z",
+ "etag": "abcdef0123A=",
+ "name": "projects/${projectNumber}/secrets/secret-${uniqueId}",
+ "replication": {
+ "userManaged": {
+ "replicas": [
+ {
+ "location": "us-central1"
+ }
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/e2e/testdata/scenarios/secretmanagerversionalias/_http02.log b/tests/e2e/testdata/scenarios/secretmanagerversionalias/_http02.log
new file mode 100644
index 0000000000..e601f4a707
--- /dev/null
+++ b/tests/e2e/testdata/scenarios/secretmanagerversionalias/_http02.log
@@ -0,0 +1,38 @@
+POST https://secretmanager.googleapis.com/v1/projects/${projectId}/secrets/secret-${uniqueId}:addVersion?%24alt=json%3Benum-encoding%3Dint
+Content-Type: application/json
+User-Agent: kcc/controller-manager
+x-goog-request-params: parent=projects%2F${projectId}%2Fsecrets%2Fsecret-${uniqueId}
+
+{
+ "parent": "projects/${projectId}/secrets/secret-${uniqueId}",
+ "payload": {
+ "data": "SSBhbHdheXMgbG92ZWQgc3BhcnJpbmcgd2l0aCBnaWFudCBjYW5keSBzd29yZHMsIGJ1dCBJIGhhZCBubyBpZGVhIHRoYXQgd2FzIG15IHN1cGVyIHNlY3JldCBpbmZvcm1hdGlvbiE="
+ }
+}
+
+200 OK
+Cache-Control: private
+Content-Type: application/json; charset=UTF-8
+Server: ESF
+Vary: Origin
+Vary: X-Origin
+Vary: Referer
+X-Content-Type-Options: nosniff
+X-Frame-Options: SAMEORIGIN
+X-Xss-Protection: 0
+
+{
+ "createTime": "2024-04-01T12:34:56.123456Z",
+ "etag": "abcdef0123A=",
+ "name": "projects/${projectNumber}/secrets/secret-${uniqueId}/versions/1",
+ "replicationStatus": {
+ "userManaged": {
+ "replicas": [
+ {
+ "location": "us-central1"
+ }
+ ]
+ }
+ },
+ "state": 1
+}
\ No newline at end of file
diff --git a/tests/e2e/testdata/scenarios/secretmanagerversionalias/_http03.log b/tests/e2e/testdata/scenarios/secretmanagerversionalias/_http03.log
new file mode 100644
index 0000000000..753cd936ab
--- /dev/null
+++ b/tests/e2e/testdata/scenarios/secretmanagerversionalias/_http03.log
@@ -0,0 +1,118 @@
+GET https://secretmanager.googleapis.com/v1/projects/${projectId}/secrets/secret-${uniqueId}?%24alt=json%3Benum-encoding%3Dint
+Content-Type: application/json
+User-Agent: kcc/controller-manager
+x-goog-request-params: name=projects%2F${projectId}%2Fsecrets%2Fsecret-${uniqueId}
+
+200 OK
+Cache-Control: private
+Content-Type: application/json; charset=UTF-8
+Server: ESF
+Vary: Origin
+Vary: X-Origin
+Vary: Referer
+X-Content-Type-Options: nosniff
+X-Frame-Options: SAMEORIGIN
+X-Xss-Protection: 0
+
+{
+ "createTime": "2024-04-01T12:34:56.123456Z",
+ "etag": "abcdef0123A=",
+ "name": "projects/${projectNumber}/secrets/secret-${uniqueId}",
+ "replication": {
+ "userManaged": {
+ "replicas": [
+ {
+ "location": "us-central1"
+ }
+ ]
+ }
+ }
+}
+
+---
+
+PATCH https://secretmanager.googleapis.com/v1/projects/${projectId}/secrets/secret-${uniqueId}?%24alt=json%3Benum-encoding%3Dint&updateMask=versionAliases
+Content-Type: application/json
+User-Agent: kcc/controller-manager
+x-goog-request-params: secret.name=projects%2F${projectId}%2Fsecrets%2Fsecret-${uniqueId}
+
+{
+ "etag": "abcdef0123A=",
+ "name": "projects/${projectId}/secrets/secret-${uniqueId}",
+ "replication": {
+ "userManaged": {
+ "replicas": [
+ {
+ "location": "us-central1"
+ }
+ ]
+ }
+ },
+ "versionAliases": {
+ "foo": "1"
+ }
+}
+
+200 OK
+Cache-Control: private
+Content-Type: application/json; charset=UTF-8
+Server: ESF
+Vary: Origin
+Vary: X-Origin
+Vary: Referer
+X-Content-Type-Options: nosniff
+X-Frame-Options: SAMEORIGIN
+X-Xss-Protection: 0
+
+{
+ "createTime": "2024-04-01T12:34:56.123456Z",
+ "etag": "abcdef0123A=",
+ "name": "projects/${projectNumber}/secrets/secret-${uniqueId}",
+ "replication": {
+ "userManaged": {
+ "replicas": [
+ {
+ "location": "us-central1"
+ }
+ ]
+ }
+ },
+ "versionAliases": {
+ "foo": "1"
+ }
+}
+
+---
+
+GET https://secretmanager.googleapis.com/v1/projects/${projectId}/secrets/secret-${uniqueId}?alt=json
+Content-Type: application/json
+User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager
+
+200 OK
+Cache-Control: private
+Content-Type: application/json; charset=UTF-8
+Server: ESF
+Vary: Origin
+Vary: X-Origin
+Vary: Referer
+X-Content-Type-Options: nosniff
+X-Frame-Options: SAMEORIGIN
+X-Xss-Protection: 0
+
+{
+ "createTime": "2024-04-01T12:34:56.123456Z",
+ "etag": "abcdef0123A=",
+ "name": "projects/${projectNumber}/secrets/secret-${uniqueId}",
+ "replication": {
+ "userManaged": {
+ "replicas": [
+ {
+ "location": "us-central1"
+ }
+ ]
+ }
+ },
+ "versionAliases": {
+ "foo": "1"
+ }
+}
\ No newline at end of file
diff --git a/tests/e2e/testdata/scenarios/secretmanagerversionalias/_object00.yaml b/tests/e2e/testdata/scenarios/secretmanagerversionalias/_object00.yaml
new file mode 100644
index 0000000000..9cc8d72e7f
--- /dev/null
+++ b/tests/e2e/testdata/scenarios/secretmanagerversionalias/_object00.yaml
@@ -0,0 +1,29 @@
+apiVersion: secretmanager.cnrm.cloud.google.com/v1beta1
+kind: SecretManagerSecret
+metadata:
+ annotations:
+ alpha.cnrm.cloud.google.com/reconciler: direct
+ cnrm.cloud.google.com/management-conflict-prevention-policy: none
+ cnrm.cloud.google.com/project-id: ${projectId}
+ finalizers:
+ - cnrm.cloud.google.com/finalizer
+ - cnrm.cloud.google.com/deletion-defender
+ generation: 1
+ name: secret-${uniqueId}
+ namespace: ${projectId}
+spec:
+ replication:
+ userManaged:
+ replicas:
+ - location: us-central1
+status:
+ conditions:
+ - lastTransitionTime: "1970-01-01T00:00:00Z"
+ message: The resource is up to date
+ reason: UpToDate
+ status: "True"
+ type: Ready
+ externalRef: projects/${projectId}/secrets/secret-${uniqueId}
+ name: projects/${projectNumber}/secrets/secret-${uniqueId}
+ observedGeneration: 1
+ observedState: {}
diff --git a/tests/e2e/testdata/scenarios/secretmanagerversionalias/_object01.yaml b/tests/e2e/testdata/scenarios/secretmanagerversionalias/_object01.yaml
new file mode 100644
index 0000000000..9a25f8a10f
--- /dev/null
+++ b/tests/e2e/testdata/scenarios/secretmanagerversionalias/_object01.yaml
@@ -0,0 +1,10 @@
+apiVersion: v1
+data:
+ secretData: SSBhbHdheXMgbG92ZWQgc3BhcnJpbmcgd2l0aCBnaWFudCBjYW5keSBzd29yZHMsIGJ1dCBJIGhhZCBubyBpZGVhIHRoYXQgd2FzIG15IHN1cGVyIHNlY3JldCBpbmZvcm1hdGlvbiE=
+kind: Secret
+metadata:
+ annotations:
+ cnrm.cloud.google.com/project-id: ${projectId}
+ name: secret-dep-${uniqueId}
+ namespace: ${projectId}
+type: Opaque
diff --git a/tests/e2e/testdata/scenarios/secretmanagerversionalias/_object02.yaml b/tests/e2e/testdata/scenarios/secretmanagerversionalias/_object02.yaml
new file mode 100644
index 0000000000..06b1fa2451
--- /dev/null
+++ b/tests/e2e/testdata/scenarios/secretmanagerversionalias/_object02.yaml
@@ -0,0 +1,40 @@
+apiVersion: secretmanager.cnrm.cloud.google.com/v1beta1
+kind: SecretManagerSecretVersion
+metadata:
+ annotations:
+ cnrm.cloud.google.com/management-conflict-prevention-policy: none
+ cnrm.cloud.google.com/project-id: ${projectId}
+ finalizers:
+ - cnrm.cloud.google.com/finalizer
+ - cnrm.cloud.google.com/deletion-defender
+ generation: 1
+ name: secretversion-${uniqueId}
+ namespace: ${projectId}
+spec:
+ enabled: true
+ secretData:
+ valueFrom:
+ secretKeyRef:
+ key: secretData
+ name: secret-dep-${uniqueId}
+ secretRef:
+ name: secret-${uniqueId}
+status:
+ conditions:
+ - lastTransitionTime: "1970-01-01T00:00:00Z"
+ message: The resource is up to date
+ reason: UpToDate
+ status: "True"
+ type: Ready
+ createTime: "1970-01-01T00:00:00Z"
+ externalRef: projects/${projectId}/secrets/secret-${uniqueId}/versions/1
+ name: projects/${projectNumber}/secrets/secret-${uniqueId}/versions/1
+ observedGeneration: 1
+ observedState:
+ createTime: "1970-01-01T00:00:00Z"
+ name: projects/${projectNumber}/secrets/secret-${uniqueId}/versions/1
+ replicationStatus:
+ userManaged:
+ replicas:
+ - location: us-central1
+ version: "1"
diff --git a/tests/e2e/testdata/scenarios/secretmanagerversionalias/_object03.yaml b/tests/e2e/testdata/scenarios/secretmanagerversionalias/_object03.yaml
new file mode 100644
index 0000000000..7308e8d9d8
--- /dev/null
+++ b/tests/e2e/testdata/scenarios/secretmanagerversionalias/_object03.yaml
@@ -0,0 +1,33 @@
+apiVersion: secretmanager.cnrm.cloud.google.com/v1beta1
+kind: SecretManagerSecret
+metadata:
+ annotations:
+ alpha.cnrm.cloud.google.com/reconciler: direct
+ cnrm.cloud.google.com/management-conflict-prevention-policy: none
+ cnrm.cloud.google.com/project-id: ${projectId}
+ finalizers:
+ - cnrm.cloud.google.com/finalizer
+ - cnrm.cloud.google.com/deletion-defender
+ generation: 2
+ name: secret-${uniqueId}
+ namespace: ${projectId}
+spec:
+ replication:
+ userManaged:
+ replicas:
+ - location: us-central1
+ versionAliases:
+ foo: "1"
+status:
+ conditions:
+ - lastTransitionTime: "1970-01-01T00:00:00Z"
+ message: The resource is up to date
+ reason: UpToDate
+ status: "True"
+ type: Ready
+ externalRef: projects/${projectId}/secrets/secret-${uniqueId}
+ name: projects/${projectNumber}/secrets/secret-${uniqueId}
+ observedGeneration: 2
+ observedState:
+ versionAliases:
+ foo: "1"
diff --git a/tests/e2e/testdata/scenarios/secretmanagerversionalias/script.yaml b/tests/e2e/testdata/scenarios/secretmanagerversionalias/script.yaml
new file mode 100644
index 0000000000..adf902598a
--- /dev/null
+++ b/tests/e2e/testdata/scenarios/secretmanagerversionalias/script.yaml
@@ -0,0 +1,64 @@
+# Copyright 2024 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: secretmanager.cnrm.cloud.google.com/v1beta1
+kind: SecretManagerSecret
+metadata:
+ annotations:
+ cnrm.cloud.google.com/project-id: ${projectId}
+ alpha.cnrm.cloud.google.com/reconciler: "direct"
+ name: secret-${uniqueId}
+spec:
+ replication:
+ userManaged:
+ replicas:
+ - location: us-central1
+---
+apiVersion: v1
+kind: Secret
+metadata:
+ name: secret-dep-${uniqueId}
+data:
+ secretData: SSBhbHdheXMgbG92ZWQgc3BhcnJpbmcgd2l0aCBnaWFudCBjYW5keSBzd29yZHMsIGJ1dCBJIGhhZCBubyBpZGVhIHRoYXQgd2FzIG15IHN1cGVyIHNlY3JldCBpbmZvcm1hdGlvbiE=
+---
+apiVersion: secretmanager.cnrm.cloud.google.com/v1beta1
+kind: SecretManagerSecretVersion
+metadata:
+ annotations:
+ cnrm.cloud.google.com/project-id: ${projectId}
+ name: secretversion-${uniqueId}
+spec:
+ enabled: true
+ secretData:
+ valueFrom:
+ secretKeyRef:
+ key: secretData
+ name: secret-dep-${uniqueId}
+ secretRef:
+ name: secret-${uniqueId}
+---
+# Verify the versionAliases has been updated
+apiVersion: secretmanager.cnrm.cloud.google.com/v1beta1
+kind: SecretManagerSecret
+metadata:
+ annotations:
+ cnrm.cloud.google.com/project-id: ${projectId}
+ alpha.cnrm.cloud.google.com/reconciler: "direct"
+ name: secret-${uniqueId}
+spec:
+ replication:
+ userManaged:
+ replicas:
+ - location: us-central1
+ versionAliases:
+ "foo": "1"
\ No newline at end of file