@@ -22,15 +22,22 @@ import (
2222 iampb "cloud.google.com/go/iam/apiv1/iampb"
2323 api "cloud.google.com/go/security/privateca/apiv1"
2424 pb "cloud.google.com/go/security/privateca/apiv1/privatecapb"
25+ "google.golang.org/protobuf/types/known/fieldmaskpb"
2526 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2627 "k8s.io/apimachinery/pkg/runtime"
28+ "k8s.io/klog/v2"
2729
2830 krm "github.com/GoogleCloudPlatform/k8s-config-connector/apis/privateca/v1beta1"
2931 refs "github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs/v1beta1"
3032 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/config"
3133 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct"
34+ "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/common"
3235 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/directbase"
3336 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/registry"
37+ "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/tags"
38+ "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/label"
39+ "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/mappers"
40+ "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/structuredreporting"
3441)
3542
3643func init () {
@@ -57,7 +64,7 @@ type caPoolAdapter struct {
5764 location string
5865 caPoolID string
5966
60- desired * krm. PrivateCACAPool
67+ desired * pb. CaPool
6168 actual * pb.CaPool
6269 caClient * api.CertificateAuthorityClient
6370}
@@ -78,6 +85,11 @@ func (m *caPoolModel) AdapterForObject(ctx context.Context, op *directbase.Adapt
7885 return nil , fmt .Errorf ("error converting to %T: %w" , obj , err )
7986 }
8087
88+ // Always call common.NormalizeReferences to resolve references
89+ if err := common .NormalizeReferences (ctx , reader , obj , nil ); err != nil {
90+ return nil , fmt .Errorf ("normalizing references: %w" , err )
91+ }
92+
8193 resourceID := direct .ValueOf (obj .Spec .ResourceID )
8294 if resourceID == "" {
8395 resourceID = obj .GetName ()
@@ -100,11 +112,18 @@ func (m *caPoolModel) AdapterForObject(ctx context.Context, op *directbase.Adapt
100112 return nil , fmt .Errorf ("cannot resolve project" )
101113 }
102114
115+ mapCtx := & direct.MapContext {}
116+ desired := PrivateCACAPoolSpec_ToProto (mapCtx , & obj .Spec )
117+ if mapCtx .Err () != nil {
118+ return nil , mapCtx .Err ()
119+ }
120+ desired .Labels = label .NewGCPLabelsFromK8sLabels (u .GetLabels ())
121+
103122 return & caPoolAdapter {
104123 caPoolID : resourceID ,
105124 location : location ,
106125 projectID : projectID ,
107- desired : obj ,
126+ desired : desired ,
108127 caClient : caClient ,
109128 }, nil
110129}
@@ -136,22 +155,129 @@ func (m *caPoolModel) AdapterForURL(ctx context.Context, url string) (directbase
136155
137156// Delete implements the Adapter interface.
138157func (a * caPoolAdapter ) Delete (ctx context.Context , deleteOp * directbase.DeleteOperation ) (bool , error ) {
139- return false , fmt .Errorf ("not implemented" )
158+ log := klog .FromContext (ctx )
159+ log .V (2 ).Info ("deleting PrivateCACAPool" , "name" , a .fullyQualifiedName ())
160+
161+ req := & pb.DeleteCaPoolRequest {Name : a .fullyQualifiedName ()}
162+ op , err := a .caClient .DeleteCaPool (ctx , req )
163+ if err != nil {
164+ if direct .IsNotFound (err ) {
165+ log .V (2 ).Info ("skipping delete for non-existent PrivateCACAPool, assuming it was already deleted" , "name" , a .fullyQualifiedName ())
166+ return true , nil
167+ }
168+ return false , fmt .Errorf ("deleting PrivateCACAPool %s: %w" , a .fullyQualifiedName (), err )
169+ }
170+ log .V (2 ).Info ("successfully deleted PrivateCACAPool" , "name" , a .fullyQualifiedName ())
171+
172+ err = op .Wait (ctx )
173+ if err != nil {
174+ return false , fmt .Errorf ("waiting delete PrivateCACAPool %s: %w" , a .fullyQualifiedName (), err )
175+ }
176+ return true , nil
140177}
141178
142179// Create implements the Adapter interface.
143180func (a * caPoolAdapter ) Create (ctx context.Context , createOp * directbase.CreateOperation ) error {
144- return fmt .Errorf ("not implemented" )
181+ log := klog .FromContext (ctx )
182+ log .V (2 ).Info ("creating PrivateCACAPool" , "id" , a .fullyQualifiedName ())
183+
184+ parent := fmt .Sprintf ("projects/%s/locations/%s" , a .projectID , a .location )
185+
186+ req := & pb.CreateCaPoolRequest {
187+ Parent : parent ,
188+ CaPoolId : a .caPoolID ,
189+ CaPool : a .desired ,
190+ }
191+ op , err := a .caClient .CreateCaPool (ctx , req )
192+ if err != nil {
193+ return fmt .Errorf ("creating PrivateCACAPool %s: %w" , a .fullyQualifiedName (), err )
194+ }
195+ created , err := op .Wait (ctx )
196+ if err != nil {
197+ return fmt .Errorf ("waiting PrivateCACAPool %s creation: %w" , a .fullyQualifiedName (), err )
198+ }
199+ log .V (2 ).Info ("successfully created PrivateCACAPool" , "name" , a .fullyQualifiedName ())
200+
201+ return a .updateStatus (ctx , createOp , created )
145202}
146203
147204// Update implements the Adapter interface.
148205func (a * caPoolAdapter ) Update (ctx context.Context , updateOp * directbase.UpdateOperation ) error {
149- return fmt .Errorf ("not implemented" )
206+ log := klog .FromContext (ctx )
207+ log .V (2 ).Info ("updating PrivateCACAPool" , "name" , a .fullyQualifiedName ())
208+
209+ diffs , updateMask , err := comparePrivateCACAPool (ctx , a .actual , a .desired )
210+ if err != nil {
211+ return err
212+ }
213+
214+ latest := a .actual
215+ if diffs .HasDiff () {
216+ diffs .Object = updateOp .GetUnstructured ()
217+ structuredreporting .ReportDiff (ctx , diffs )
218+
219+ a .desired .Name = a .fullyQualifiedName ()
220+ req := & pb.UpdateCaPoolRequest {
221+ UpdateMask : updateMask ,
222+ CaPool : a .desired ,
223+ }
224+ op , err := a .caClient .UpdateCaPool (ctx , req )
225+ if err != nil {
226+ return fmt .Errorf ("updating PrivateCACAPool %s: %w" , a .fullyQualifiedName (), err )
227+ }
228+ updated , err := op .Wait (ctx )
229+ if err != nil {
230+ return fmt .Errorf ("waiting update PrivateCACAPool %s: %w" , a .fullyQualifiedName (), err )
231+ }
232+ log .V (2 ).Info ("successfully updated PrivateCACAPool" , "name" , a .fullyQualifiedName ())
233+ latest = updated
234+ }
235+
236+ return a .updateStatus (ctx , updateOp , latest )
150237}
151238
152239// Export implements the Adapter interface.
153240func (a * caPoolAdapter ) Export (ctx context.Context ) (* unstructured.Unstructured , error ) {
154- return nil , fmt .Errorf ("not implemented" )
241+ if a .actual == nil {
242+ return nil , fmt .Errorf ("Find() not called" )
243+ }
244+ u := & unstructured.Unstructured {}
245+
246+ obj := & krm.PrivateCACAPool {}
247+ mapCtx := & direct.MapContext {}
248+ obj .Spec = direct .ValueOf (PrivateCACAPoolSpec_FromProto (mapCtx , a .actual ))
249+ if mapCtx .Err () != nil {
250+ return nil , mapCtx .Err ()
251+ }
252+
253+ obj .Spec .ProjectRef = & refs.ProjectRef {Name : a .projectID }
254+ obj .Spec .Location = a .location
255+ uObj , err := runtime .DefaultUnstructuredConverter .ToUnstructured (obj )
256+ if err != nil {
257+ return nil , err
258+ }
259+ u .Object = uObj
260+ u .SetName (a .actual .Name )
261+ u .SetGroupVersionKind (krm .PrivateCACAPoolGVK )
262+ return u , nil
263+ }
264+
265+ func comparePrivateCACAPool (ctx context.Context , actual , desired * pb.CaPool ) (* structuredreporting.Diff , * fieldmaskpb.FieldMask , error ) {
266+ maskedActual , err := mappers .OnlySpecFields (actual , PrivateCACAPoolSpec_FromProto , PrivateCACAPoolSpec_ToProto )
267+ if err != nil {
268+ return nil , nil , err
269+ }
270+ maskedActual .Name = desired .Name
271+ diffs , updateMask , err := tags .DiffForTopLevelFields (ctx , desired .ProtoReflect (), maskedActual .ProtoReflect ())
272+ if err != nil {
273+ return nil , nil , err
274+ }
275+ return diffs , updateMask , nil
276+ }
277+
278+ func (a * caPoolAdapter ) updateStatus (ctx context.Context , op directbase.Operation , latest * pb.CaPool ) error {
279+ status := & krm.PrivateCACAPoolStatus {}
280+ return op .UpdateStatus (ctx , status , nil )
155281}
156282
157283// Find implements the Adapter interface.
0 commit comments