@@ -3,25 +3,28 @@ package reconciler
3
3
import (
4
4
"context"
5
5
"fmt"
6
+ "hash/fnv"
6
7
"time"
7
8
8
9
controllerclient "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/controller-runtime/client"
9
10
10
11
"github.com/operator-framework/api/pkg/operators/v1alpha1"
12
+ hashutil "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/hash"
11
13
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
12
14
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorlister"
13
15
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil"
14
16
"github.com/pkg/errors"
15
17
"github.com/sirupsen/logrus"
16
18
corev1 "k8s.io/api/core/v1"
17
- v1 "k8s.io/api/core/v1"
18
19
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
19
20
"k8s.io/apimachinery/pkg/labels"
20
21
"k8s.io/apimachinery/pkg/util/intstr"
22
+ "k8s.io/apimachinery/pkg/util/rand"
21
23
)
22
24
23
25
const (
24
26
CatalogSourceUpdateKey = "catalogsource.operators.coreos.com/update"
27
+ ServiceHashLabelKey = "olm.service-spec-hash"
25
28
CatalogPollingRequeuePeriod = 30 * time .Second
26
29
)
27
30
@@ -57,14 +60,14 @@ func (s *grpcCatalogSourceDecorator) Labels() map[string]string {
57
60
}
58
61
}
59
62
60
- func (s * grpcCatalogSourceDecorator ) Service () * v1 .Service {
61
- svc := & v1 .Service {
63
+ func (s * grpcCatalogSourceDecorator ) Service () * corev1 .Service {
64
+ svc := & corev1 .Service {
62
65
ObjectMeta : metav1.ObjectMeta {
63
66
Name : s .GetName (),
64
67
Namespace : s .GetNamespace (),
65
68
},
66
- Spec : v1 .ServiceSpec {
67
- Ports : []v1 .ServicePort {
69
+ Spec : corev1 .ServiceSpec {
70
+ Ports : []corev1 .ServicePort {
68
71
{
69
72
Name : "grpc" ,
70
73
Port : 50051 ,
@@ -74,11 +77,16 @@ func (s *grpcCatalogSourceDecorator) Service() *v1.Service {
74
77
Selector : s .Labels (),
75
78
},
76
79
}
80
+
81
+ labels := map [string ]string {}
82
+ hash := HashServiceSpec (svc .Spec )
83
+ labels [ServiceHashLabelKey ] = hash
84
+ svc .SetLabels (labels )
77
85
ownerutil .AddOwner (svc , s .CatalogSource , false , false )
78
86
return svc
79
87
}
80
88
81
- func (s * grpcCatalogSourceDecorator ) Pod () * v1 .Pod {
89
+ func (s * grpcCatalogSourceDecorator ) Pod () * corev1 .Pod {
82
90
pod := Pod (s .CatalogSource , "registry-server" , s .Spec .Image , s .Labels (), 5 , 10 )
83
91
ownerutil .AddOwner (pod , s .CatalogSource , false , false )
84
92
return pod
@@ -93,7 +101,7 @@ type GrpcRegistryReconciler struct {
93
101
94
102
var _ RegistryReconciler = & GrpcRegistryReconciler {}
95
103
96
- func (c * GrpcRegistryReconciler ) currentService (source grpcCatalogSourceDecorator ) * v1 .Service {
104
+ func (c * GrpcRegistryReconciler ) currentService (source grpcCatalogSourceDecorator ) * corev1 .Service {
97
105
serviceName := source .Service ().GetName ()
98
106
service , err := c .Lister .CoreV1 ().ServiceLister ().Services (source .GetNamespace ()).Get (serviceName )
99
107
if err != nil {
@@ -103,7 +111,7 @@ func (c *GrpcRegistryReconciler) currentService(source grpcCatalogSourceDecorato
103
111
return service
104
112
}
105
113
106
- func (c * GrpcRegistryReconciler ) currentPods (source grpcCatalogSourceDecorator ) []* v1 .Pod {
114
+ func (c * GrpcRegistryReconciler ) currentPods (source grpcCatalogSourceDecorator ) []* corev1 .Pod {
107
115
pods , err := c .Lister .CoreV1 ().PodLister ().Pods (source .GetNamespace ()).List (source .Selector ())
108
116
if err != nil {
109
117
logrus .WithError (err ).Warn ("couldn't find pod in cache" )
@@ -115,7 +123,7 @@ func (c *GrpcRegistryReconciler) currentPods(source grpcCatalogSourceDecorator)
115
123
return pods
116
124
}
117
125
118
- func (c * GrpcRegistryReconciler ) currentUpdatePods (source grpcCatalogSourceDecorator ) []* v1 .Pod {
126
+ func (c * GrpcRegistryReconciler ) currentUpdatePods (source grpcCatalogSourceDecorator ) []* corev1 .Pod {
119
127
pods , err := c .Lister .CoreV1 ().PodLister ().Pods (source .GetNamespace ()).List (source .SelectorForUpdate ())
120
128
if err != nil {
121
129
logrus .WithError (err ).Warn ("couldn't find pod in cache" )
@@ -127,13 +135,13 @@ func (c *GrpcRegistryReconciler) currentUpdatePods(source grpcCatalogSourceDecor
127
135
return pods
128
136
}
129
137
130
- func (c * GrpcRegistryReconciler ) currentPodsWithCorrectImage (source grpcCatalogSourceDecorator ) []* v1 .Pod {
138
+ func (c * GrpcRegistryReconciler ) currentPodsWithCorrectImage (source grpcCatalogSourceDecorator ) []* corev1 .Pod {
131
139
pods , err := c .Lister .CoreV1 ().PodLister ().Pods (source .GetNamespace ()).List (labels .SelectorFromValidatedSet (source .Labels ()))
132
140
if err != nil {
133
141
logrus .WithError (err ).Warn ("couldn't find pod in cache" )
134
142
return nil
135
143
}
136
- found := []* v1 .Pod {}
144
+ found := []* corev1 .Pod {}
137
145
for _ , p := range pods {
138
146
if p .Spec .Containers [0 ].Image == source .Spec .Image {
139
147
found = append (found , p )
@@ -262,8 +270,9 @@ func (c *GrpcRegistryReconciler) ensureUpdatePod(source grpcCatalogSourceDecorat
262
270
263
271
func (c * GrpcRegistryReconciler ) ensureService (source grpcCatalogSourceDecorator , overwrite bool ) error {
264
272
service := source .Service ()
265
- if c .currentService (source ) != nil {
266
- if ! overwrite {
273
+ svc := c .currentService (source )
274
+ if svc != nil {
275
+ if ! overwrite && ServiceHashMatch (svc , service ) {
267
276
return nil
268
277
}
269
278
if err := c .OpClient .DeleteService (service .GetNamespace (), service .GetName (), metav1 .NewDeleteOptions (0 )); err != nil {
@@ -274,6 +283,39 @@ func (c *GrpcRegistryReconciler) ensureService(source grpcCatalogSourceDecorator
274
283
return err
275
284
}
276
285
286
+ // ServiceHashMatch will check the hash info in existing Service to ensure its
287
+ // hash info matches the desired Service's hash.
288
+ func ServiceHashMatch (existing , new * corev1.Service ) bool {
289
+ labels := existing .GetLabels ()
290
+ newLabels := new .GetLabels ()
291
+ if len (labels ) == 0 || len (newLabels ) == 0 {
292
+ return false
293
+ }
294
+
295
+ existingSvcSpecHash , ok := labels [ServiceHashLabelKey ]
296
+ if ! ok {
297
+ return false
298
+ }
299
+
300
+ newSvcSpecHash , ok := newLabels [ServiceHashLabelKey ]
301
+ if ! ok {
302
+ return false
303
+ }
304
+
305
+ if existingSvcSpecHash != newSvcSpecHash {
306
+ return false
307
+ }
308
+
309
+ return true
310
+ }
311
+
312
+ // HashServiceSpec calculates a hash given a copy of the service spec
313
+ func HashServiceSpec (spec corev1.ServiceSpec ) string {
314
+ hasher := fnv .New32a ()
315
+ hashutil .DeepHashObject (hasher , & spec )
316
+ return rand .SafeEncodeString (fmt .Sprint (hasher .Sum32 ()))
317
+ }
318
+
277
319
// createUpdatePod is an internal method that creates a pod using the latest catalog source.
278
320
func (c * GrpcRegistryReconciler ) createUpdatePod (source grpcCatalogSourceDecorator ) (* corev1.Pod , error ) {
279
321
// remove label from pod to ensure service does not accidentally route traffic to the pod
@@ -343,7 +385,7 @@ func (c *GrpcRegistryReconciler) CheckRegistryServer(catalogSource *v1alpha1.Cat
343
385
// By updating the catalog on cluster it promotes the update pod to act as the new version of the catalog on-cluster.
344
386
func (c * GrpcRegistryReconciler ) promoteCatalog (updatePod * corev1.Pod , key string ) error {
345
387
// Update the update pod to promote it to serving pod via the SSA client
346
- err := c .SSAClient .Apply (context .TODO (), updatePod , func (p * v1 .Pod ) error {
388
+ err := c .SSAClient .Apply (context .TODO (), updatePod , func (p * corev1 .Pod ) error {
347
389
p .Labels [CatalogSourceLabelKey ] = key
348
390
p .Labels [CatalogSourceUpdateKey ] = ""
349
391
return nil
0 commit comments