1010// Red Hat, Inc. - initial API and implementation
1111//
1212
13- package utils
13+ package sync
1414
1515import (
1616 "context"
1717 "fmt"
1818 "reflect"
1919
20+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+ "k8s.io/apimachinery/pkg/types"
22+ "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
23+
2024 ctrl "sigs.k8s.io/controller-runtime"
2125
2226 "k8s.io/apimachinery/pkg/api/errors"
@@ -29,29 +33,74 @@ var (
2933)
3034
3135type Syncer interface {
36+ // Create creates object.
37+ // Return true if a new object is created, otherwise returns false.
38+ // Returns error if object cannot be created otherwise returns nil.
39+ Create (context context.Context , blueprint client.Object , owner metav1.Object ) (bool , error )
40+ // CreateIgnoreIfExists creates object.
41+ // Return true if a new object is created or object already exists, otherwise returns false.
42+ // Returns error if object cannot be created otherwise returns nil.
43+ CreateIgnoreIfExists (context context.Context , blueprint client.Object , owner metav1.Object ) (bool , error )
3244 // Get gets object.
3345 // Returns true if object exists otherwise returns false.
3446 // Returns error if object cannot be retrieved otherwise returns nil.
35- Get (key client.ObjectKey , objectMeta client.Object ) (bool , error )
36- // Delete does delete object by key.
47+ Get (context context.Context , key client.ObjectKey , objectMeta client.Object ) (bool , error )
48+ // GetClusterScoped gets cluster scoped object by name
49+ // Returns true if object exists otherwise returns false.
50+ // Returns error if object cannot be retrieved otherwise returns nil.
51+ GetClusterScoped (context context.Context , name string , objectMeta client.Object ) (bool , error )
52+ // Delete deletes object by key.
3753 // Returns true if object deleted or not found otherwise returns false.
3854 // Returns error if object cannot be deleted otherwise returns nil.
3955 Delete (context context.Context , key client.ObjectKey , objectMeta client.Object ) (bool , error )
56+ // DeleteClusterClusterScoped deletes cluster scoped object by name.
57+ // Returns true if object deleted or not found otherwise returns false.
58+ // Returns error if object cannot be deleted otherwise returns nil.
59+ DeleteClusterClusterScoped (context context.Context , name string , objectMeta client.Object ) (bool , error )
4060}
4161
4262type ObjSyncer struct {
4363 syncer Syncer
4464 cli client.Client
65+ scheme * runtime.Scheme
66+ }
67+
68+ func (s ObjSyncer ) Create (context context.Context , blueprint client.Object , owner metav1.Object ) (bool , error ) {
69+ if owner != nil {
70+ if err := controllerutil .SetControllerReference (owner , blueprint , s .scheme ); err != nil {
71+ return false , fmt .Errorf ("failed to set controller reference: %w" , err )
72+ }
73+ }
74+
75+ return s .doCreate (context , blueprint , false )
76+ }
77+
78+ func (s ObjSyncer ) CreateIgnoreIfExists (context context.Context , blueprint client.Object , owner metav1.Object ) (bool , error ) {
79+ if owner != nil {
80+ if err := controllerutil .SetControllerReference (owner , blueprint , s .scheme ); err != nil {
81+ return false , fmt .Errorf ("failed to set controller reference: %w" , err )
82+ }
83+ }
84+
85+ return s .doCreate (context , blueprint , true )
4586}
4687
4788func (s ObjSyncer ) Get (context context.Context , key client.ObjectKey , objectMeta client.Object ) (bool , error ) {
4889 return s .doGetIgnoreNotFound (context , key , objectMeta )
4990}
5091
92+ func (s ObjSyncer ) GetClusterScoped (context context.Context , name string , objectMeta client.Object ) (bool , error ) {
93+ return s .doGetIgnoreNotFound (context , types.NamespacedName {Name : name }, objectMeta )
94+ }
95+
5196func (s ObjSyncer ) Delete (context context.Context , key client.ObjectKey , objectMeta client.Object ) (bool , error ) {
5297 return s .deleteByKeyIgnoreNotFound (context , key , objectMeta )
5398}
5499
100+ func (s ObjSyncer ) DeleteClusterClusterScoped (context context.Context , name string , objectMeta client.Object ) (bool , error ) {
101+ return s .deleteByKeyIgnoreNotFound (context , types.NamespacedName {Name : name }, objectMeta )
102+ }
103+
55104// deleteByKeyIgnoreNotFound deletes object by key.
56105// Returns true if object deleted or not found otherwise returns false.
57106// Returns error if object cannot be deleted otherwise returns nil.
@@ -107,6 +156,29 @@ func (s ObjSyncer) doGetIgnoreNotFound(
107156 }
108157}
109158
159+ // doCreate creates object.
160+ // Returns true if object created or already exists otherwise returns false.
161+ // Return error if object cannot be created otherwise returns nil.
162+ func (s ObjSyncer ) doCreate (
163+ context context.Context ,
164+ blueprint client.Object ,
165+ ignoreIfAlreadyExists bool ,
166+ ) (bool , error ) {
167+ if err := s .cli .Create (context , blueprint ); err == nil {
168+ syncLog .Info ("Object created" , "namespace" , blueprint .GetNamespace (), "kind" , GetObjectType (blueprint ), "name" , blueprint .GetName ())
169+ return true , nil
170+ } else if errors .IsAlreadyExists (err ) {
171+ if ignoreIfAlreadyExists {
172+ syncLog .Info ("Object already exists, ignoring" , "namespace" , blueprint .GetNamespace (), "kind" , GetObjectType (blueprint ), "name" , blueprint .GetName ())
173+ return true , nil
174+ } else {
175+ return false , err
176+ }
177+ } else {
178+ return false , err
179+ }
180+ }
181+
110182func GetObjectType (obj interface {}) string {
111183 objType := reflect .TypeOf (obj ).String ()
112184 if reflect .TypeOf (obj ).Kind ().String () == "ptr" {
0 commit comments