Skip to content

Commit 052ba18

Browse files
committed
Adds OLM Operator Plugin interface and CSV Namespace labeller plug-in
Signed-off-by: perdasilva <[email protected]> Upstream-repository: perdasilva Upstream-commit: baaafa10f8d9f5c3251bfccb207c20bb84cdbc80 Signed-off-by: perdasilva <[email protected]>
1 parent 1264b81 commit 052ba18

File tree

7 files changed

+717
-0
lines changed

7 files changed

+717
-0
lines changed
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
package olm
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/operator-framework/api/pkg/operators/v1alpha1"
9+
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/internal/pruning"
10+
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubestate"
11+
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer"
12+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13+
"k8s.io/apimachinery/pkg/util/sets"
14+
"k8s.io/client-go/informers"
15+
v12 "k8s.io/client-go/listers/core/v1"
16+
"k8s.io/client-go/tools/cache"
17+
"k8s.io/client-go/util/workqueue"
18+
)
19+
20+
const NamespaceLabelSyncerLabelKey = "security.openshift.io/scc.podSecurityLabelSync"
21+
22+
// systemNSSyncExemptions is the list of namespaces deployed by an OpenShift install
23+
// payload, as retrieved by listing the namespaces after a successful installation
24+
// IMPORTANT: The Namespace openshift-operators must be an exception to this rule
25+
// since it is used by OCP/OLM users to install their Operator bundle solutions.
26+
var systemNSSyncExemptions = sets.NewString(
27+
// kube-specific system namespaces
28+
"default",
29+
"kube-node-lease",
30+
"kube-public",
31+
"kube-system",
32+
33+
// openshift payload namespaces
34+
"openshift",
35+
"openshift-apiserver",
36+
"openshift-apiserver-operator",
37+
"openshift-authentication",
38+
"openshift-authentication-operator",
39+
"openshift-cloud-controller-manager",
40+
"openshift-cloud-controller-manager-operator",
41+
"openshift-cloud-credential-operator",
42+
"openshift-cloud-network-config-controller",
43+
"openshift-cluster-csi-drivers",
44+
"openshift-cluster-machine-approver",
45+
"openshift-cluster-node-tuning-operator",
46+
"openshift-cluster-samples-operator",
47+
"openshift-cluster-storage-operator",
48+
"openshift-cluster-version",
49+
"openshift-config",
50+
"openshift-config-managed",
51+
"openshift-config-operator",
52+
"openshift-console",
53+
"openshift-console-operator",
54+
"openshift-console-user-settings",
55+
"openshift-controller-manager",
56+
"openshift-controller-manager-operator",
57+
"openshift-dns",
58+
"openshift-dns-operator",
59+
"openshift-etcd",
60+
"openshift-etcd-operator",
61+
"openshift-host-network",
62+
"openshift-image-registry",
63+
"openshift-infra",
64+
"openshift-ingress",
65+
"openshift-ingress-canary",
66+
"openshift-ingress-operator",
67+
"openshift-insights",
68+
"openshift-kni-infra",
69+
"openshift-kube-apiserver",
70+
"openshift-kube-apiserver-operator",
71+
"openshift-kube-controller-manager",
72+
"openshift-kube-controller-manager-operator",
73+
"openshift-kube-scheduler",
74+
"openshift-kube-scheduler-operator",
75+
"openshift-kube-storage-version-migrator",
76+
"openshift-kube-storage-version-migrator-operator",
77+
"openshift-machine-api",
78+
"openshift-machine-config-operator",
79+
"openshift-marketplace",
80+
"openshift-monitoring",
81+
"openshift-multus",
82+
"openshift-network-diagnostics",
83+
"openshift-network-operator",
84+
"openshift-node",
85+
"openshift-nutanix-infra",
86+
"openshift-oauth-apiserver",
87+
"openshift-openstack-infra",
88+
"openshift-operator-lifecycle-manager",
89+
"openshift-ovirt-infra",
90+
"openshift-sdn",
91+
"openshift-service-ca",
92+
"openshift-service-ca-operator",
93+
"openshift-user-workload-monitoring",
94+
"openshift-vsphere-infra",
95+
)
96+
97+
// csvNamespaceLabelerPlugin is responsible for labeling non-payload openshift-* namespaces
98+
// with the label "security.openshift.io/scc.podSecurityLabelSync=true" so that the PSA Label Syncer
99+
// see https://github.com/openshift/cluster-policy-controller/blob/master/pkg/psalabelsyncer/podsecurity_label_sync_controller.go
100+
// can help ensure that the operator payloads in the namespace continue to work even if they don't yet respect the
101+
// upstream Pod Security Admission controller, which will become active in k8s 1.15.
102+
// see https://kubernetes.io/docs/concepts/security/pod-security-admission/
103+
// If a CSV is created or modified, this controller will look at the csv's namespace. If it is a non-payload namespace,
104+
// if the namespace name is prefixed with 'openshift-', and if the namespace does not contain the label (whatever
105+
// value it may be set to), it will add the "security.openshift.io/scc.podSecurityLabelSync=true" to the namespace.
106+
type csvNamespaceLabelerPlugin struct {
107+
operator *Operator
108+
namespaceLister v12.NamespaceLister
109+
}
110+
111+
func (p *csvNamespaceLabelerPlugin) Init(ctx context.Context, config *operatorConfig, op *Operator) error {
112+
if op == nil {
113+
return fmt.Errorf("cannot initialize plugin: operator undefined")
114+
}
115+
116+
p.operator = op
117+
118+
for _, namespace := range config.watchedNamespaces {
119+
120+
// create a namespace informer for namespaces that do not include
121+
// the label syncer label
122+
namespaceInformer := informers.NewSharedInformerFactoryWithOptions(
123+
op.opClient.KubernetesInterface(),
124+
config.resyncPeriod(),
125+
informers.WithNamespace(namespace),
126+
).Core().V1().Namespaces()
127+
128+
if err := op.RegisterInformer(namespaceInformer.Informer()); err != nil {
129+
return err
130+
}
131+
p.namespaceLister = namespaceInformer.Lister()
132+
133+
// create a new csv informer and prune status to reduce memory footprint
134+
csvNamespaceLabelerInformer := cache.NewSharedIndexInformer(
135+
pruning.NewListerWatcher(
136+
op.client,
137+
namespace,
138+
func(opts *metav1.ListOptions) {
139+
opts.LabelSelector = fmt.Sprintf("!%s", v1alpha1.CopiedLabelKey)
140+
},
141+
pruning.PrunerFunc(func(csv *v1alpha1.ClusterServiceVersion) {
142+
*csv = v1alpha1.ClusterServiceVersion{
143+
TypeMeta: csv.TypeMeta,
144+
ObjectMeta: csv.ObjectMeta,
145+
}
146+
}),
147+
),
148+
&v1alpha1.ClusterServiceVersion{},
149+
config.resyncPeriod(),
150+
cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
151+
)
152+
153+
csvNamespaceLabelerPluginQueue := workqueue.NewNamedRateLimitingQueue(
154+
workqueue.DefaultControllerRateLimiter(),
155+
fmt.Sprintf("%s/csv-ns-labeler-plugin", namespace),
156+
)
157+
csvNamespaceLabelerPluginQueueInformer, err := queueinformer.NewQueueInformer(
158+
ctx,
159+
queueinformer.WithInformer(csvNamespaceLabelerInformer),
160+
queueinformer.WithLogger(op.logger),
161+
queueinformer.WithQueue(csvNamespaceLabelerPluginQueue),
162+
queueinformer.WithIndexer(op.csvIndexers[namespace]),
163+
queueinformer.WithSyncer(p),
164+
)
165+
if err != nil {
166+
return err
167+
}
168+
if err := op.RegisterQueueInformer(csvNamespaceLabelerPluginQueueInformer); err != nil {
169+
return err
170+
}
171+
}
172+
173+
return nil
174+
}
175+
176+
func (p *csvNamespaceLabelerPlugin) Sync(ctx context.Context, event kubestate.ResourceEvent) error {
177+
// only act on csv added and updated events
178+
if event.Type() != kubestate.ResourceAdded && event.Type() != kubestate.ResourceUpdated {
179+
return nil
180+
}
181+
182+
csv, ok := event.Resource().(*v1alpha1.ClusterServiceVersion)
183+
if !ok {
184+
return fmt.Errorf("event resource is not a ClusterServiceVersion")
185+
}
186+
187+
if p.operator == nil {
188+
return fmt.Errorf("plugin has not been correctly initialized: operator undefined")
189+
}
190+
191+
// ignore copied csvs
192+
// informer should already be filtering these out - but just in case
193+
if csv.IsCopied() {
194+
return nil
195+
}
196+
197+
// ignore non-openshift-* and payload openshift-* namespaces
198+
if !strings.HasPrefix(csv.GetNamespace(), "openshift-") || systemNSSyncExemptions.Has(csv.GetNamespace()) {
199+
return nil
200+
}
201+
202+
namespace, err := p.namespaceLister.Get(csv.GetNamespace())
203+
if err != nil {
204+
return fmt.Errorf("error getting csv namespace (%s) for label sync'er labeling", csv.GetNamespace())
205+
}
206+
207+
// add label sync'er label if it does not exist
208+
if _, ok := namespace.GetLabels()[NamespaceLabelSyncerLabelKey]; !ok {
209+
nsCopy := namespace.DeepCopy()
210+
if nsCopy.GetLabels() == nil {
211+
nsCopy.SetLabels(map[string]string{})
212+
}
213+
nsCopy.GetLabels()[NamespaceLabelSyncerLabelKey] = "true"
214+
if _, err := p.operator.opClient.KubernetesInterface().CoreV1().Namespaces().Update(ctx, nsCopy, metav1.UpdateOptions{}); err != nil {
215+
return fmt.Errorf("error updating csv namespace (%s) with label sync'er label", nsCopy.GetNamespace())
216+
}
217+
218+
if p.operator.logger != nil {
219+
p.operator.logger.Printf("applied %s=true label to namespace %s", NamespaceLabelSyncerLabelKey, nsCopy.GetNamespace())
220+
}
221+
}
222+
223+
return nil
224+
}

0 commit comments

Comments
 (0)