Skip to content

Commit f2a484d

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 f6981f9 commit f2a484d

File tree

9 files changed

+747
-3
lines changed

9 files changed

+747
-3
lines changed
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
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+
func newCsvNamespaceLabelerPlugIn() OperatorPlugin {
98+
return &csvNamespaceLabelerPlugin{}
99+
}
100+
101+
// csvNamespaceLabelerPlugin is responsible for labeling non-payload openshift-* namespaces
102+
// with the label "security.openshift.io/scc.podSecurityLabelSync=true" so that the PSA Label Syncer
103+
// see https://github.com/openshift/cluster-policy-controller/blob/master/pkg/psalabelsyncer/podsecurity_label_sync_controller.go
104+
// can help ensure that the operator payloads in the namespace continue to work even if they don't yet respect the
105+
// upstream Pod Security Admission controller, which will become active in k8s 1.15.
106+
// see https://kubernetes.io/docs/concepts/security/pod-security-admission/
107+
// If a CSV is created or modified, this controller will look at the csv's namespace. If it is a non-payload namespace,
108+
// if the namespace name is prefixed with 'openshift-', and if the namespace does not contain the label (whatever
109+
// value it may be set to), it will add the "security.openshift.io/scc.podSecurityLabelSync=true" to the namespace.
110+
type csvNamespaceLabelerPlugin struct {
111+
operator *Operator
112+
namespaceLister v12.NamespaceLister
113+
}
114+
115+
func (p *csvNamespaceLabelerPlugin) Init(ctx context.Context, config *operatorConfig, op *Operator) error {
116+
if op == nil {
117+
return fmt.Errorf("cannot initialize plugin: operator undefined")
118+
}
119+
120+
p.operator = op
121+
122+
for _, namespace := range config.watchedNamespaces {
123+
124+
// create a namespace informer for namespaces that do not include
125+
// the label syncer label
126+
namespaceInformer := informers.NewSharedInformerFactoryWithOptions(
127+
op.opClient.KubernetesInterface(),
128+
config.resyncPeriod(),
129+
informers.WithNamespace(namespace),
130+
).Core().V1().Namespaces()
131+
132+
if err := op.RegisterInformer(namespaceInformer.Informer()); err != nil {
133+
return err
134+
}
135+
p.namespaceLister = namespaceInformer.Lister()
136+
137+
// create a new csv informer and prune status to reduce memory footprint
138+
csvNamespaceLabelerInformer := cache.NewSharedIndexInformer(
139+
pruning.NewListerWatcher(
140+
op.client,
141+
namespace,
142+
func(opts *metav1.ListOptions) {
143+
opts.LabelSelector = fmt.Sprintf("!%s", v1alpha1.CopiedLabelKey)
144+
},
145+
pruning.PrunerFunc(func(csv *v1alpha1.ClusterServiceVersion) {
146+
*csv = v1alpha1.ClusterServiceVersion{
147+
TypeMeta: csv.TypeMeta,
148+
ObjectMeta: csv.ObjectMeta,
149+
}
150+
}),
151+
),
152+
&v1alpha1.ClusterServiceVersion{},
153+
config.resyncPeriod(),
154+
cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
155+
)
156+
157+
csvNamespaceLabelerPluginQueue := workqueue.NewNamedRateLimitingQueue(
158+
workqueue.DefaultControllerRateLimiter(),
159+
fmt.Sprintf("%s/csv-ns-labeler-plugin", namespace),
160+
)
161+
csvNamespaceLabelerPluginQueueInformer, err := queueinformer.NewQueueInformer(
162+
ctx,
163+
queueinformer.WithInformer(csvNamespaceLabelerInformer),
164+
queueinformer.WithLogger(op.logger),
165+
queueinformer.WithQueue(csvNamespaceLabelerPluginQueue),
166+
queueinformer.WithIndexer(op.csvIndexers[namespace]),
167+
queueinformer.WithSyncer(p),
168+
)
169+
if err != nil {
170+
return err
171+
}
172+
if err := op.RegisterQueueInformer(csvNamespaceLabelerPluginQueueInformer); err != nil {
173+
return err
174+
}
175+
}
176+
177+
return nil
178+
}
179+
180+
func (p *csvNamespaceLabelerPlugin) Sync(ctx context.Context, event kubestate.ResourceEvent) error {
181+
// only act on csv added and updated events
182+
if event.Type() != kubestate.ResourceAdded && event.Type() != kubestate.ResourceUpdated {
183+
return nil
184+
}
185+
186+
csv, ok := event.Resource().(*v1alpha1.ClusterServiceVersion)
187+
if !ok {
188+
return fmt.Errorf("event resource is not a ClusterServiceVersion")
189+
}
190+
191+
if p.operator == nil {
192+
return fmt.Errorf("plugin has not been correctly initialized: operator undefined")
193+
}
194+
195+
// ignore copied csvs
196+
// informer should already be filtering these out - but just in case
197+
if csv.IsCopied() {
198+
return nil
199+
}
200+
201+
// ignore non-openshift-* and payload openshift-* namespaces
202+
if !strings.HasPrefix(csv.GetNamespace(), "openshift-") || systemNSSyncExemptions.Has(csv.GetNamespace()) {
203+
return nil
204+
}
205+
206+
namespace, err := p.namespaceLister.Get(csv.GetNamespace())
207+
if err != nil {
208+
return fmt.Errorf("error getting csv namespace (%s) for label sync'er labeling", csv.GetNamespace())
209+
}
210+
211+
// add label sync'er label if it does not exist
212+
if _, ok := namespace.GetLabels()[NamespaceLabelSyncerLabelKey]; !ok {
213+
nsCopy := namespace.DeepCopy()
214+
if nsCopy.GetLabels() == nil {
215+
nsCopy.SetLabels(map[string]string{})
216+
}
217+
nsCopy.GetLabels()[NamespaceLabelSyncerLabelKey] = "true"
218+
if _, err := p.operator.opClient.KubernetesInterface().CoreV1().Namespaces().Update(ctx, nsCopy, metav1.UpdateOptions{}); err != nil {
219+
return fmt.Errorf("error updating csv namespace (%s) with label sync'er label", nsCopy.GetNamespace())
220+
}
221+
222+
if p.operator.logger != nil {
223+
p.operator.logger.Printf("applied %s=true label to namespace %s", NamespaceLabelSyncerLabelKey, nsCopy.GetNamespace())
224+
}
225+
}
226+
227+
return nil
228+
}

0 commit comments

Comments
 (0)