Skip to content

Commit 017bae2

Browse files
Merge pull request GoogleCloudPlatform#2797 from yuwenma/secret-manager-3-controller-2
feat: direct controller for SecretManagerSecret (part 1)
2 parents d4cc447 + 1ccd159 commit 017bae2

File tree

28 files changed

+6115
-299
lines changed

28 files changed

+6115
-299
lines changed

apis/secretmanager/v1beta1/secretmanagersecret_types.go

+3-18
Original file line numberDiff line numberDiff line change
@@ -39,24 +39,9 @@ type SecretManagerSecretSpec struct {
3939
// The replication policy cannot be changed after the Secret has been created.
4040
Replication *Replication `json:"replication,omitempty"`
4141

42-
/*NOTYET
43-
// The labels assigned to this Secret.
44-
//
45-
// Label keys must be between 1 and 63 characters long, have a UTF-8 encoding
46-
// of maximum 128 bytes, and must conform to the following PCRE regular
47-
// expression: `[\p{Ll}\p{Lo}][\p{Ll}\p{Lo}\p{N}_-]{0,62}`
48-
//
49-
// Label values must be between 0 and 63 characters long, have a UTF-8
50-
// encoding of maximum 128 bytes, and must conform to the following PCRE
51-
// regular expression: `[\p{Ll}\p{Lo}\p{N}_-]{0,63}`
52-
//
53-
// No more than 64 labels can be assigned to a given resource.
54-
Labels map[string]string `json:"labels,omitempty"`
55-
*/
56-
5742
// Optional. A list of up to 10 Pub/Sub topics to which messages are published
5843
// when control plane operations are called on the secret or its versions.
59-
TopicRefs []TopicRef `json:"topics,omitempty"`
44+
TopicRefs []*TopicRef `json:"topics,omitempty"`
6045

6146
// Optional. Timestamp in UTC when the
6247
// [Secret][google.cloud.secretmanager.v1.Secret] is scheduled to expire.
@@ -125,7 +110,7 @@ type SecretManagerSecretSpec struct {
125110

126111
type TopicRef struct {
127112
// +required
128-
PubSubTopicRef refv1beta1.PubSubTopicRef `json:"topicRef,omitempty"`
113+
PubSubTopicRef *refv1beta1.PubSubTopicRef `json:"topicRef,omitempty"`
129114
}
130115

131116
// +kcc:proto=google.cloud.secretmanager.v1.CustomerManagedEncryption
@@ -144,7 +129,7 @@ type CustomerManagedEncryption struct {
144129
// replication policy type, Cloud KMS CryptoKeys must reside in `global`.
145130
//
146131
// The expected format is `projects/*/locations/*/keyRings/*/cryptoKeys/*`.
147-
KmsKeyRef refv1beta1.KMSCryptoKeyRef `json:"kmsKeyRef,omitempty"`
132+
KmsKeyRef *refv1beta1.KMSCryptoKeyRef `json:"kmsKeyRef,omitempty"`
148133
}
149134

150135
// SecretManagerSecretStatus defines the config connector machine state of SecretManagerSecret

apis/secretmanager/v1beta1/zz_generated.deepcopy.go

+22-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dev/tasks/run-e2e

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ echo "Downloading envtest assets..."
2424
export KUBEBUILDER_ASSETS=$(go run sigs.k8s.io/controller-runtime/tools/setup-envtest@latest use -p path)
2525

2626
if [[ -z "${KCC_USE_DIRECT_RECONCILERS:-}" ]]; then
27-
KCC_USE_DIRECT_RECONCILERS=ComputeForwardingRule,GKEHubFeatureMembership
27+
KCC_USE_DIRECT_RECONCILERS=ComputeForwardingRule,GKEHubFeatureMembership,SecretManagerSecret
2828
fi
2929
echo "Using direct controllers: $KCC_USE_DIRECT_RECONCILERS"
3030
export KCC_USE_DIRECT_RECONCILERS

dev/tools/controllerbuilder/generate.sh

+17-8
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,6 @@ go run . generate-types \
3333
--kind DataflowFlexTemplateJob \
3434
--proto-resource FlexTemplateRuntimeEnvironment
3535

36-
go run main.go generate-types \
37-
--service google.cloud.secretmanager.v1 \
38-
--proto-source-path ../proto-to-mapper/build/googleapis.pb \
39-
--output-api ${APIS_DIR} \
40-
--kind SecretManagerSecret \
41-
--proto-resource Secret \
42-
--api-version "secretmanager.cnrm.cloud.google.com/v1beta1"
43-
4436
go run . generate-mapper \
4537
--proto-source-path ../proto-to-mapper/build/googleapis.pb \
4638
--service google.dataflow.v1beta3 \
@@ -203,5 +195,22 @@ go run . generate-mapper \
203195
--output-dir ${OUTPUT_MAPPER} \
204196
--api-dir ${APIS_DIR}
205197

198+
# SecretManager
199+
go run main.go generate-types \
200+
--service google.cloud.secretmanager.v1 \
201+
--proto-source-path ../proto-to-mapper/build/googleapis.pb \
202+
--output-api ${APIS_DIR} \
203+
--kind SecretManagerSecret \
204+
--proto-resource Secret \
205+
--api-version "secretmanager.cnrm.cloud.google.com/v1beta1"
206+
207+
go run . generate-mapper \
208+
--proto-source-path ../proto-to-mapper/build/googleapis.pb \
209+
--service google.cloud.secretmanager.v1 \
210+
--api-version "secretmanager.cnrm.cloud.google.com/v1beta1" \
211+
--api-go-package-path $REPO_ROOT/apis/ \
212+
--output-dir $REPO_ROOT/pkg/controller/direct/ \
213+
--api-dir $REPO_ROOT/apis/
214+
206215
# Fix up formatting
207216
${REPO_ROOT}/dev/tasks/fix-gofmt

dev/tools/controllerbuilder/template/apis/refs.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ func (r *{{.Kind}}Ref) NormalizedExternal(ctx context.Context, reader client.Rea
8080
if err != nil {
8181
return "", fmt.Errorf("reading status.externalRef: %w", err)
8282
}
83-
if actualExternalRef == ""
83+
if actualExternalRef == "" {
8484
return "", k8s.NewReferenceNotReadyError(u.GroupVersionKind(), key)
8585
}
8686
r.External = actualExternalRef

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ require (
2121
cloud.google.com/go/profiler v0.4.1
2222
cloud.google.com/go/redis v1.17.0
2323
cloud.google.com/go/resourcemanager v1.10.0
24+
cloud.google.com/go/secretmanager v1.14.0
2425
cloud.google.com/go/securesourcemanager v1.1.1
2526
cloud.google.com/go/security v1.18.0
2627
cloud.google.com/go/workstations v1.1.1

go.sum

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mockgcp/mocksecretmanager/secrets.go

+32-10
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package mocksecretmanager
1616

1717
import (
1818
"context"
19+
"fmt"
1920
"strconv"
2021
"strings"
2122

@@ -62,22 +63,30 @@ func (s *SecretsV1) CreateSecret(ctx context.Context, req *pb.CreateSecretReques
6263
obj.Name = fqn
6364
obj.CreateTime = timestamppb.Now()
6465
if obj.Replication == nil {
65-
obj.Replication = &pb.Replication{}
66-
}
67-
if obj.Replication.Replication == nil {
68-
obj.Replication.Replication = &pb.Replication_Automatic_{
69-
Automatic: &pb.Replication_Automatic{},
70-
}
66+
return nil, fmt.Errorf("Secret.replication must be specified.")
7167
}
7268
obj.Etag = computeEtag(obj)
73-
69+
if err := s.populateDefaultsForSecret(ctx, obj); err != nil {
70+
return nil, err
71+
}
7472
if err := s.storage.Create(ctx, fqn, obj); err != nil {
7573
return nil, err
7674
}
7775

7876
return obj, nil
7977
}
8078

79+
func (s *SecretsV1) populateDefaultsForSecret(ctx context.Context, obj *pb.Secret) error {
80+
for _, version := range obj.VersionAliases {
81+
versionName := obj.Name + "/versions/" + strconv.FormatInt(version, 64)
82+
_, err := s.GetSecretVersion(ctx, &pb.GetSecretVersionRequest{Name: versionName})
83+
if err != nil {
84+
return fmt.Errorf("Aliases cannot be assigned to versions that don't exist")
85+
}
86+
}
87+
return nil
88+
}
89+
8190
// Gets metadata for a given [Secret][google.cloud.secretmanager.v1.Secret].
8291
func (s *SecretsV1) GetSecret(ctx context.Context, req *pb.GetSecretRequest) (*pb.Secret, error) {
8392
name, err := s.parseSecretName(req.Name)
@@ -122,28 +131,41 @@ func (s *SecretsV1) UpdateSecret(ctx context.Context, req *pb.UpdateSecretReques
122131
if len(paths) == 0 {
123132
return nil, status.Errorf(codes.InvalidArgument, "update_mask is required")
124133
}
125-
// TODO: Some sort of helper for fieldmask?
126134
for _, path := range paths {
127135
switch path {
128136
case "topics":
129137
updated.Topics = req.Secret.GetTopics()
130-
case "customer_managed_encryption":
138+
case "customerManagedEncryption":
131139
updated.CustomerManagedEncryption = req.Secret.GetCustomerManagedEncryption()
132140
case "rotation":
133141
updated.Rotation = req.Secret.GetRotation()
142+
if len(req.Secret.GetTopics()) == 0 {
143+
return nil, fmt.Errorf("There must be at least one topic configured when a Rotation policy is set.")
144+
}
145+
case "rotation.rotationPeriod":
146+
updated.Rotation.RotationPeriod = req.Secret.GetRotation().RotationPeriod
134147
case "annotations":
135148
updated.Annotations = req.Secret.GetAnnotations()
136149
case "labels":
137150
updated.Labels = req.Secret.GetLabels()
138-
case "version_aliases":
151+
case "versionAliases":
139152
updated.VersionAliases = req.Secret.GetVersionAliases()
153+
case "expireTime":
154+
updated.Expiration = &pb.Secret_ExpireTime{
155+
ExpireTime: req.Secret.GetExpireTime(),
156+
}
140157
case "expiration":
141158
updated.Expiration = req.Secret.GetExpiration()
159+
case "rotation.nextRotationTime":
160+
updated.Rotation.NextRotationTime = req.Secret.Rotation.NextRotationTime
142161
default:
143162
return nil, status.Errorf(codes.InvalidArgument, "update_mask path %q not valid", path)
144163
}
145164
}
146165

166+
if err := s.populateDefaultsForSecret(ctx, updated); err != nil {
167+
return nil, err
168+
}
147169
if err := s.storage.Update(ctx, fqn, updated); err != nil {
148170
return nil, err
149171
}

0 commit comments

Comments
 (0)