Skip to content

Commit 5d2816a

Browse files
authored
Pull secret from ServiceAccounts and skip checks for controllers having zero replicas (deckhouse#37)
* extract ImagePullSecrets from ServiceAccount if no of them are found in the controller specs * skip checks for controllers having zero replicas
1 parent 15fe5fd commit 5d2816a

File tree

4 files changed

+86
-25
lines changed

4 files changed

+86
-25
lines changed

deploy/rbac.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ rules:
1212
- list
1313
- watch
1414
- get
15+
- apiGroups:
16+
- ""
17+
resources:
18+
- serviceaccounts
19+
verbs:
20+
- get
1521
- apiGroups:
1622
- extensions
1723
- apps

helm/k8s-image-availability-exporter/templates/rbac.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ rules:
1212
- list
1313
- watch
1414
- get
15+
- apiGroups:
16+
- ""
17+
resources:
18+
- serviceaccounts
19+
verbs:
20+
- get
1521
- apiGroups:
1622
- extensions
1723
- apps

pkg/registry_checker/checker.go

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package registry_checker
33
import (
44
"crypto/tls"
55
"errors"
6+
appsv1 "k8s.io/api/apps/v1"
67
"k8s.io/apimachinery/pkg/util/wait"
78
"net/http"
89
"sync"
@@ -34,11 +35,11 @@ type RegistryChecker struct {
3435

3536
imageStore *store.ImageStore
3637

37-
deploymentsInformer appsv1informers.DeploymentInformer
38-
statefulSetssInformer appsv1informers.StatefulSetInformer
39-
daemonSetsInformer appsv1informers.DaemonSetInformer
40-
cronJobsInformer v1beta1.CronJobInformer
41-
secretsInformer corev1informers.SecretInformer
38+
deploymentsInformer appsv1informers.DeploymentInformer
39+
statefulSetsInformer appsv1informers.StatefulSetInformer
40+
daemonSetsInformer appsv1informers.DaemonSetInformer
41+
cronJobsInformer v1beta1.CronJobInformer
42+
secretsInformer corev1informers.SecretInformer
4243

4344
controllerIndexers ControllerIndexers
4445

@@ -47,6 +48,8 @@ type RegistryChecker struct {
4748
imageExistsVectors []prometheus.Metric
4849

4950
registryTransport *http.Transport
51+
52+
kubeClient *kubernetes.Clientset
5053
}
5154

5255
func NewRegistryChecker(
@@ -68,15 +71,17 @@ func NewRegistryChecker(
6871
rc := &RegistryChecker{
6972
imageStore: store.NewImageStore(),
7073

71-
deploymentsInformer: informerFactory.Apps().V1().Deployments(),
72-
statefulSetssInformer: informerFactory.Apps().V1().StatefulSets(),
73-
daemonSetsInformer: informerFactory.Apps().V1().DaemonSets(),
74-
cronJobsInformer: informerFactory.Batch().V1beta1().CronJobs(),
75-
secretsInformer: informerFactory.Core().V1().Secrets(),
74+
deploymentsInformer: informerFactory.Apps().V1().Deployments(),
75+
statefulSetsInformer: informerFactory.Apps().V1().StatefulSets(),
76+
daemonSetsInformer: informerFactory.Apps().V1().DaemonSets(),
77+
cronJobsInformer: informerFactory.Batch().V1beta1().CronJobs(),
78+
secretsInformer: informerFactory.Core().V1().Secrets(),
7679

7780
ignoredImages: map[string]struct{}{},
7881

7982
registryTransport: customTransport,
83+
84+
kubeClient: kubeClient,
8085
}
8186

8287
for _, image := range ignoredImages {
@@ -105,7 +110,7 @@ func (rc *RegistryChecker) Run(stopCh <-chan struct{}) {
105110
rc.controllerIndexers.deploymentIndexer = rc.deploymentsInformer.Informer().GetIndexer()
106111
go rc.deploymentsInformer.Informer().Run(stopCh)
107112

108-
rc.statefulSetssInformer.Informer().AddEventHandlerWithResyncPeriod(cache.ResourceEventHandlerFuncs{
113+
rc.statefulSetsInformer.Informer().AddEventHandlerWithResyncPeriod(cache.ResourceEventHandlerFuncs{
109114
AddFunc: func(obj interface{}) {
110115
rc.reconcile(obj)
111116
},
@@ -116,12 +121,12 @@ func (rc *RegistryChecker) Run(stopCh <-chan struct{}) {
116121
rc.reconcile(obj)
117122
},
118123
}, resyncPeriod)
119-
err = rc.statefulSetssInformer.Informer().AddIndexers(statefulSetIndexers)
124+
err = rc.statefulSetsInformer.Informer().AddIndexers(statefulSetIndexers)
120125
if err != nil {
121126
panic(err)
122127
}
123-
rc.controllerIndexers.statefulSetIndexer = rc.statefulSetssInformer.Informer().GetIndexer()
124-
go rc.statefulSetssInformer.Informer().Run(stopCh)
128+
rc.controllerIndexers.statefulSetIndexer = rc.statefulSetsInformer.Informer().GetIndexer()
129+
go rc.statefulSetsInformer.Informer().Run(stopCh)
125130

126131
rc.daemonSetsInformer.Informer().AddEventHandlerWithResyncPeriod(cache.ResourceEventHandlerFuncs{
127132
AddFunc: func(obj interface{}) {
@@ -163,7 +168,7 @@ func (rc *RegistryChecker) Run(stopCh <-chan struct{}) {
163168
go rc.secretsInformer.Informer().Run(stopCh)
164169

165170
logrus.Info("Waiting for cache sync")
166-
cache.WaitForCacheSync(stopCh, rc.deploymentsInformer.Informer().HasSynced, rc.statefulSetssInformer.Informer().HasSynced,
171+
cache.WaitForCacheSync(stopCh, rc.deploymentsInformer.Informer().HasSynced, rc.statefulSetsInformer.Informer().HasSynced,
167172
rc.daemonSetsInformer.Informer().HasSynced, rc.cronJobsInformer.Informer().HasSynced, rc.secretsInformer.Informer().HasSynced)
168173
logrus.Info("Caches populated successfully")
169174
}
@@ -180,7 +185,24 @@ func (rc *RegistryChecker) reconcile(obj interface{}) {
180185
continue
181186
}
182187

183-
if !rc.controllerIndexers.CheckImageExistence(image) {
188+
var skipObject bool
189+
190+
switch typedObj := obj.(type) {
191+
case *appsv1.Deployment:
192+
if typedObj.Status.Replicas == 0 {
193+
skipObject = true
194+
}
195+
case *appsv1.StatefulSet:
196+
if typedObj.Status.Replicas == 0 {
197+
skipObject = true
198+
}
199+
case *appsv1.DaemonSet:
200+
if typedObj.Status.CurrentNumberScheduled == 0 {
201+
skipObject = true
202+
}
203+
}
204+
205+
if skipObject || !rc.controllerIndexers.CheckImageExistence(image) {
184206
rc.imageStore.RemoveImage(image)
185207
continue
186208
}
@@ -190,7 +212,7 @@ func (rc *RegistryChecker) reconcile(obj interface{}) {
190212
}
191213

192214
func (rc *RegistryChecker) reconcileUpdate(a, b interface{}) {
193-
if !EqualObjects(a, b) {
215+
if EqualObjects(a, b) {
194216
return
195217
}
196218

@@ -203,7 +225,7 @@ func (rc *RegistryChecker) Check() {
203225

204226
var processingGroup sync.WaitGroup
205227
for _, image := range oldImages {
206-
keyChain := rc.controllerIndexers.GetKeychainForImage(image)
228+
keyChain := rc.controllerIndexers.GetKeychainForImage(rc.kubeClient, image)
207229

208230
// TODO: backoff
209231
processingGroup.Add(1)

pkg/registry_checker/indexers.go

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package registry_checker
22

33
import (
44
"fmt"
5+
"k8s.io/client-go/kubernetes"
56
"reflect"
67

78
"github.com/flant/k8s-image-availability-exporter/pkg/store"
@@ -90,6 +91,14 @@ func extractPullSecretRefsFromPodSpec(namespace string, spec corev1.PodSpec) (re
9091
return
9192
}
9293

94+
func extractPullSecretRefsFromServiceAccount(namespace string, spec corev1.ServiceAccount) (ret []string) {
95+
for _, ref := range spec.ImagePullSecrets {
96+
ret = append(ret, namespace+"/"+ref.Name)
97+
}
98+
99+
return
100+
}
101+
93102
func ExtractImages(obj interface{}) ([]string, error) {
94103
switch typedObj := obj.(type) {
95104
case *appsv1.Deployment:
@@ -120,20 +129,38 @@ func ExtractContainerInfos(image string, obj interface{}) []store.ContainerInfo
120129
}
121130
}
122131

123-
func ExtractPullSecretRefs(obj interface{}) (ret []string) {
132+
func ExtractPullSecretRefs(kubeClient *kubernetes.Clientset, obj interface{}) (ret []string) {
133+
var (
134+
namespace string
135+
podSpec corev1.PodSpec
136+
)
137+
124138
switch typedObj := obj.(type) {
125139
case *appsv1.Deployment:
126-
ret = append(ret, extractPullSecretRefsFromPodSpec(typedObj.Namespace, typedObj.Spec.Template.Spec)...)
140+
namespace = typedObj.Namespace
141+
podSpec = typedObj.Spec.Template.Spec
127142
case *appsv1.StatefulSet:
128-
ret = append(ret, extractPullSecretRefsFromPodSpec(typedObj.Namespace, typedObj.Spec.Template.Spec)...)
143+
namespace = typedObj.Namespace
144+
podSpec = typedObj.Spec.Template.Spec
129145
case *appsv1.DaemonSet:
130-
ret = append(ret, extractPullSecretRefsFromPodSpec(typedObj.Namespace, typedObj.Spec.Template.Spec)...)
146+
namespace = typedObj.Namespace
147+
podSpec = typedObj.Spec.Template.Spec
131148
case *batchv1beta.CronJob:
132-
ret = append(ret, extractPullSecretRefsFromPodSpec(typedObj.Namespace, typedObj.Spec.JobTemplate.Spec.Template.Spec)...)
149+
namespace = typedObj.Namespace
150+
podSpec = typedObj.Spec.JobTemplate.Spec.Template.Spec
133151
default:
134152
panic(fmt.Errorf("%q not of types *appsv1.Deployment, *appsv1.StatefulSet, *appsv1.DaemonSet, *batchv1beta.CronJob", reflect.TypeOf(typedObj)))
135153
}
136154

155+
pullSecretRefs := extractPullSecretRefsFromPodSpec(namespace, podSpec)
156+
if len(pullSecretRefs) == 0 && len(podSpec.ServiceAccountName) > 0 {
157+
serviceAccount, err := kubeClient.CoreV1().ServiceAccounts(namespace).Get(podSpec.ServiceAccountName, metav1.GetOptions{})
158+
if err == nil {
159+
pullSecretRefs = append(pullSecretRefs, extractPullSecretRefsFromServiceAccount(namespace, *serviceAccount)...)
160+
}
161+
}
162+
ret = append(ret, pullSecretRefs...)
163+
137164
return
138165
}
139166

@@ -197,12 +224,12 @@ func (ci ControllerIndexers) GetContainerInfosForImage(image string) (ret []stor
197224
return
198225
}
199226

200-
func (ci ControllerIndexers) GetKeychainForImage(image string) *keychain {
227+
func (ci ControllerIndexers) GetKeychainForImage(kubeClient *kubernetes.Clientset, image string) *keychain {
201228
objs := ci.GetObjectsByIndex(image)
202229

203230
var refSet = map[string]struct{}{}
204231
for _, obj := range objs {
205-
pullSecretRefs := ExtractPullSecretRefs(obj)
232+
pullSecretRefs := ExtractPullSecretRefs(kubeClient, obj)
206233
for _, ref := range pullSecretRefs {
207234
refSet[ref] = struct{}{}
208235
}

0 commit comments

Comments
 (0)