Skip to content

Commit 6c4e779

Browse files
authoredJul 21, 2022
Introduce protectedCopiedCSVNamespaces flag (#2811)
Problem: Users rely on Copied CSVs in order to understand which operators are available in a given namespace. When installing All Namespace operators, a Copied CSV is created in every namespace which can place a huge performance strain on clusters with many namespaces. OLM introduced the ability to disable Copied CSVs for All Namespace mode operators in an effort to resolve the performance issues on large clusters, unfortunately removing the ability for users to identify which operators are available in a given namespace. Solution: The protectedCopiedCSVNamespaces runtime flag can be used to prevent Copied CSVs from being deleted even when Copied CSVs are disabled. An admin can then provide users with the proper RBAC to view which operators are running in All Namespace mode. Signed-off-by: Alexander Greene <[email protected]>
1 parent 83e3ebf commit 6c4e779

File tree

4 files changed

+211
-87
lines changed

4 files changed

+211
-87
lines changed
 

‎cmd/olm/main.go

+4
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ var (
6060
tlsKeyPath = pflag.String(
6161
"tls-key", "", "Path to use for private key (requires tls-cert)")
6262

63+
protectedCopiedCSVNamespaces = pflag.String("protectedCopiedCSVNamespaces",
64+
"", "A comma-delimited set of namespaces where global Copied CSVs will always appear, even if Copied CSVs are disabled")
65+
6366
tlsCertPath = pflag.String(
6467
"tls-cert", "", "Path to use for certificate key (requires tls-key)")
6568

@@ -162,6 +165,7 @@ func main() {
162165
olm.WithOperatorClient(opClient),
163166
olm.WithRestConfig(config),
164167
olm.WithConfigClient(versionedConfigClient),
168+
olm.WithProtectedCopiedCSVNamespaces(*protectedCopiedCSVNamespaces),
165169
)
166170
if err != nil {
167171
logger.WithError(err).Fatal("error configuring operator")

‎pkg/controller/operators/olm/config.go

+35-20
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package olm
22

33
import (
4+
"strings"
45
"time"
56

67
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer"
@@ -21,18 +22,19 @@ import (
2122
type OperatorOption func(*operatorConfig)
2223

2324
type operatorConfig struct {
24-
resyncPeriod func() time.Duration
25-
operatorNamespace string
26-
watchedNamespaces []string
27-
clock utilclock.Clock
28-
logger *logrus.Logger
29-
operatorClient operatorclient.ClientInterface
30-
externalClient versioned.Interface
31-
strategyResolver install.StrategyResolverInterface
32-
apiReconciler APIIntersectionReconciler
33-
apiLabeler labeler.Labeler
34-
restConfig *rest.Config
35-
configClient configv1client.Interface
25+
protectedCopiedCSVNamespaces map[string]struct{}
26+
resyncPeriod func() time.Duration
27+
operatorNamespace string
28+
watchedNamespaces []string
29+
clock utilclock.Clock
30+
logger *logrus.Logger
31+
operatorClient operatorclient.ClientInterface
32+
externalClient versioned.Interface
33+
strategyResolver install.StrategyResolverInterface
34+
apiReconciler APIIntersectionReconciler
35+
apiLabeler labeler.Labeler
36+
restConfig *rest.Config
37+
configClient configv1client.Interface
3638
}
3739

3840
func (o *operatorConfig) apply(options []OperatorOption) {
@@ -77,14 +79,15 @@ func (o *operatorConfig) validate() (err error) {
7779

7880
func defaultOperatorConfig() *operatorConfig {
7981
return &operatorConfig{
80-
resyncPeriod: queueinformer.ResyncWithJitter(30*time.Second, 0.2),
81-
operatorNamespace: "default",
82-
watchedNamespaces: []string{metav1.NamespaceAll},
83-
clock: utilclock.RealClock{},
84-
logger: logrus.New(),
85-
strategyResolver: &install.StrategyResolver{},
86-
apiReconciler: APIIntersectionReconcileFunc(ReconcileAPIIntersection),
87-
apiLabeler: labeler.Func(LabelSetsFor),
82+
resyncPeriod: queueinformer.ResyncWithJitter(30*time.Second, 0.2),
83+
operatorNamespace: "default",
84+
watchedNamespaces: []string{metav1.NamespaceAll},
85+
clock: utilclock.RealClock{},
86+
logger: logrus.New(),
87+
strategyResolver: &install.StrategyResolver{},
88+
apiReconciler: APIIntersectionReconcileFunc(ReconcileAPIIntersection),
89+
apiLabeler: labeler.Func(LabelSetsFor),
90+
protectedCopiedCSVNamespaces: map[string]struct{}{},
8891
}
8992
}
9093

@@ -112,6 +115,18 @@ func WithLogger(logger *logrus.Logger) OperatorOption {
112115
}
113116
}
114117

118+
func WithProtectedCopiedCSVNamespaces(namespaces string) OperatorOption {
119+
return func(config *operatorConfig) {
120+
if namespaces == "" {
121+
return
122+
}
123+
124+
for _, ns := range strings.Split(namespaces, ",") {
125+
config.protectedCopiedCSVNamespaces[ns] = struct{}{}
126+
}
127+
}
128+
}
129+
115130
func WithClock(clock utilclock.Clock) OperatorOption {
116131
return func(config *operatorConfig) {
117132
config.clock = clock

‎pkg/controller/operators/olm/operator.go

+122-62
Original file line numberDiff line numberDiff line change
@@ -63,32 +63,33 @@ var (
6363
type Operator struct {
6464
queueinformer.Operator
6565

66-
clock utilclock.Clock
67-
logger *logrus.Logger
68-
opClient operatorclient.ClientInterface
69-
client versioned.Interface
70-
lister operatorlister.OperatorLister
71-
copiedCSVLister operatorsv1alpha1listers.ClusterServiceVersionLister
72-
ogQueueSet *queueinformer.ResourceQueueSet
73-
csvQueueSet *queueinformer.ResourceQueueSet
74-
olmConfigQueue workqueue.RateLimitingInterface
75-
csvCopyQueueSet *queueinformer.ResourceQueueSet
76-
copiedCSVGCQueueSet *queueinformer.ResourceQueueSet
77-
objGCQueueSet *queueinformer.ResourceQueueSet
78-
nsQueueSet workqueue.RateLimitingInterface
79-
apiServiceQueue workqueue.RateLimitingInterface
80-
csvIndexers map[string]cache.Indexer
81-
recorder record.EventRecorder
82-
resolver install.StrategyResolverInterface
83-
apiReconciler APIIntersectionReconciler
84-
apiLabeler labeler.Labeler
85-
csvSetGenerator csvutility.SetGenerator
86-
csvReplaceFinder csvutility.ReplaceFinder
87-
csvNotification csvutility.WatchNotification
88-
serviceAccountSyncer *scoped.UserDefinedServiceAccountSyncer
89-
clientAttenuator *scoped.ClientAttenuator
90-
serviceAccountQuerier *scoped.UserDefinedServiceAccountQuerier
91-
clientFactory clients.Factory
66+
clock utilclock.Clock
67+
logger *logrus.Logger
68+
opClient operatorclient.ClientInterface
69+
client versioned.Interface
70+
lister operatorlister.OperatorLister
71+
protectedCopiedCSVNamespaces map[string]struct{}
72+
copiedCSVLister operatorsv1alpha1listers.ClusterServiceVersionLister
73+
ogQueueSet *queueinformer.ResourceQueueSet
74+
csvQueueSet *queueinformer.ResourceQueueSet
75+
olmConfigQueue workqueue.RateLimitingInterface
76+
csvCopyQueueSet *queueinformer.ResourceQueueSet
77+
copiedCSVGCQueueSet *queueinformer.ResourceQueueSet
78+
objGCQueueSet *queueinformer.ResourceQueueSet
79+
nsQueueSet workqueue.RateLimitingInterface
80+
apiServiceQueue workqueue.RateLimitingInterface
81+
csvIndexers map[string]cache.Indexer
82+
recorder record.EventRecorder
83+
resolver install.StrategyResolverInterface
84+
apiReconciler APIIntersectionReconciler
85+
apiLabeler labeler.Labeler
86+
csvSetGenerator csvutility.SetGenerator
87+
csvReplaceFinder csvutility.ReplaceFinder
88+
csvNotification csvutility.WatchNotification
89+
serviceAccountSyncer *scoped.UserDefinedServiceAccountSyncer
90+
clientAttenuator *scoped.ClientAttenuator
91+
serviceAccountQuerier *scoped.UserDefinedServiceAccountQuerier
92+
clientFactory clients.Factory
9293
}
9394

9495
func NewOperator(ctx context.Context, options ...OperatorOption) (*Operator, error) {
@@ -121,30 +122,31 @@ func newOperatorWithConfig(ctx context.Context, config *operatorConfig) (*Operat
121122
}
122123

123124
op := &Operator{
124-
Operator: queueOperator,
125-
clock: config.clock,
126-
logger: config.logger,
127-
opClient: config.operatorClient,
128-
client: config.externalClient,
129-
ogQueueSet: queueinformer.NewEmptyResourceQueueSet(),
130-
csvQueueSet: queueinformer.NewEmptyResourceQueueSet(),
131-
olmConfigQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "olmConfig"),
132-
csvCopyQueueSet: queueinformer.NewEmptyResourceQueueSet(),
133-
copiedCSVGCQueueSet: queueinformer.NewEmptyResourceQueueSet(),
134-
objGCQueueSet: queueinformer.NewEmptyResourceQueueSet(),
135-
apiServiceQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "apiservice"),
136-
resolver: config.strategyResolver,
137-
apiReconciler: config.apiReconciler,
138-
lister: lister,
139-
recorder: eventRecorder,
140-
apiLabeler: config.apiLabeler,
141-
csvIndexers: map[string]cache.Indexer{},
142-
csvSetGenerator: csvutility.NewSetGenerator(config.logger, lister),
143-
csvReplaceFinder: csvutility.NewReplaceFinder(config.logger, config.externalClient),
144-
serviceAccountSyncer: scoped.NewUserDefinedServiceAccountSyncer(config.logger, scheme, config.operatorClient, config.externalClient),
145-
clientAttenuator: scoped.NewClientAttenuator(config.logger, config.restConfig, config.operatorClient),
146-
serviceAccountQuerier: scoped.NewUserDefinedServiceAccountQuerier(config.logger, config.externalClient),
147-
clientFactory: clients.NewFactory(config.restConfig),
125+
Operator: queueOperator,
126+
clock: config.clock,
127+
logger: config.logger,
128+
opClient: config.operatorClient,
129+
client: config.externalClient,
130+
ogQueueSet: queueinformer.NewEmptyResourceQueueSet(),
131+
csvQueueSet: queueinformer.NewEmptyResourceQueueSet(),
132+
olmConfigQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "olmConfig"),
133+
csvCopyQueueSet: queueinformer.NewEmptyResourceQueueSet(),
134+
copiedCSVGCQueueSet: queueinformer.NewEmptyResourceQueueSet(),
135+
objGCQueueSet: queueinformer.NewEmptyResourceQueueSet(),
136+
apiServiceQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "apiservice"),
137+
resolver: config.strategyResolver,
138+
apiReconciler: config.apiReconciler,
139+
lister: lister,
140+
recorder: eventRecorder,
141+
apiLabeler: config.apiLabeler,
142+
csvIndexers: map[string]cache.Indexer{},
143+
csvSetGenerator: csvutility.NewSetGenerator(config.logger, lister),
144+
csvReplaceFinder: csvutility.NewReplaceFinder(config.logger, config.externalClient),
145+
serviceAccountSyncer: scoped.NewUserDefinedServiceAccountSyncer(config.logger, scheme, config.operatorClient, config.externalClient),
146+
clientAttenuator: scoped.NewClientAttenuator(config.logger, config.restConfig, config.operatorClient),
147+
serviceAccountQuerier: scoped.NewUserDefinedServiceAccountQuerier(config.logger, config.externalClient),
148+
clientFactory: clients.NewFactory(config.restConfig),
149+
protectedCopiedCSVNamespaces: config.protectedCopiedCSVNamespaces,
148150
}
149151

150152
// Set up syncing for namespace-scoped resources
@@ -1299,20 +1301,31 @@ func (a *Operator) syncOLMConfig(obj interface{}) (syncError error) {
12991301
return err
13001302
}
13011303

1302-
// Filter to unique copies
1303-
uniqueCopiedCSVs := map[string]struct{}{}
1304+
// Create a map that points from CSV name to a map of namespaces it is copied to
1305+
// for quick lookups.
1306+
copiedCSVNamespaces := map[string]map[string]struct{}{}
13041307
for _, copiedCSV := range copiedCSVs {
1305-
uniqueCopiedCSVs[copiedCSV.GetName()] = struct{}{}
1308+
if _, ok := copiedCSVNamespaces[copiedCSV.GetName()]; !ok {
1309+
copiedCSVNamespaces[copiedCSV.GetName()] = map[string]struct{}{}
1310+
}
1311+
copiedCSVNamespaces[copiedCSV.GetName()][copiedCSV.GetNamespace()] = struct{}{}
13061312
}
13071313

13081314
csvs, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(og.GetNamespace()).List(labels.NewSelector().Add(*nonCopiedCSVRequirement))
13091315
if err != nil {
13101316
return err
13111317
}
13121318

1319+
namespaces, err := a.lister.CoreV1().NamespaceLister().List(labels.Everything())
1320+
if err != nil {
1321+
return err
1322+
}
1323+
1324+
copiedCSVEvaluatorFunc := getCopiedCSVEvaluatorFunc(olmConfig.CopiedCSVsAreEnabled(), namespaces, a.protectedCopiedCSVNamespaces)
1325+
13131326
for _, csv := range csvs {
1314-
// If the correct number of copied CSVs were found, continue
1315-
if _, ok := uniqueCopiedCSVs[csv.GetName()]; ok == olmConfig.CopiedCSVsAreEnabled() {
1327+
// Ignore NS where actual CSV is installed
1328+
if copiedCSVEvaluatorFunc(copiedCSVNamespaces[csv.GetName()]) {
13161329
continue
13171330
}
13181331

@@ -1324,7 +1337,7 @@ func (a *Operator) syncOLMConfig(obj interface{}) (syncError error) {
13241337
}
13251338

13261339
// Update the olmConfig status if it has changed.
1327-
condition := getCopiedCSVsCondition(!olmConfig.CopiedCSVsAreEnabled(), csvIsRequeued)
1340+
condition := getCopiedCSVsCondition(olmConfig.CopiedCSVsAreEnabled(), csvIsRequeued)
13281341
if !isStatusConditionPresentAndAreTypeReasonMessageStatusEqual(olmConfig.Status.Conditions, condition) {
13291342
meta.SetStatusCondition(&olmConfig.Status.Conditions, condition)
13301343
if _, err := a.client.OperatorsV1().OLMConfigs().UpdateStatus(context.TODO(), olmConfig, metav1.UpdateOptions{}); err != nil {
@@ -1335,6 +1348,37 @@ func (a *Operator) syncOLMConfig(obj interface{}) (syncError error) {
13351348
return nil
13361349
}
13371350

1351+
// getCopiedCSVEvaluatorFunc returns a function that evaluates if the a set of Copied CSVs exist in the expected namespaces.
1352+
func getCopiedCSVEvaluatorFunc(copiedCSVsEnabled bool, namespaces []*corev1.Namespace, protectedCopiedCSVNamespaces map[string]struct{}) func(map[string]struct{}) bool {
1353+
if copiedCSVsEnabled {
1354+
// Exclude the namespace hosting the original CSV
1355+
expectedCopiedCSVCount := -1
1356+
for _, ns := range namespaces {
1357+
if ns.Status.Phase == corev1.NamespaceActive {
1358+
expectedCopiedCSVCount++
1359+
}
1360+
}
1361+
return func(m map[string]struct{}) bool {
1362+
return expectedCopiedCSVCount == len(m)
1363+
}
1364+
}
1365+
1366+
// Check that Copied CSVs exist in protected namespaces.
1367+
return func(m map[string]struct{}) bool {
1368+
if len(protectedCopiedCSVNamespaces) != len(m) {
1369+
return false
1370+
}
1371+
1372+
for protectedNS := range protectedCopiedCSVNamespaces {
1373+
if _, ok := m[protectedNS]; !ok {
1374+
return false
1375+
}
1376+
}
1377+
1378+
return true
1379+
}
1380+
}
1381+
13381382
func isStatusConditionPresentAndAreTypeReasonMessageStatusEqual(conditions []metav1.Condition, condition metav1.Condition) bool {
13391383
foundCondition := meta.FindStatusCondition(conditions, condition.Type)
13401384
if foundCondition == nil {
@@ -1346,13 +1390,13 @@ func isStatusConditionPresentAndAreTypeReasonMessageStatusEqual(conditions []met
13461390
foundCondition.Status == condition.Status
13471391
}
13481392

1349-
func getCopiedCSVsCondition(isDisabled, csvIsRequeued bool) metav1.Condition {
1393+
func getCopiedCSVsCondition(enabled, csvIsRequeued bool) metav1.Condition {
13501394
condition := metav1.Condition{
13511395
Type: operatorsv1.DisabledCopiedCSVsConditionType,
13521396
LastTransitionTime: metav1.Now(),
13531397
Status: metav1.ConditionFalse,
13541398
}
1355-
if !isDisabled {
1399+
if enabled {
13561400
condition.Reason = "CopiedCSVsEnabled"
13571401
condition.Message = "Copied CSVs are enabled and present across the cluster"
13581402
if csvIsRequeued {
@@ -1361,15 +1405,14 @@ func getCopiedCSVsCondition(isDisabled, csvIsRequeued bool) metav1.Condition {
13611405
return condition
13621406
}
13631407

1408+
condition.Reason = "CopiedCSVsDisabled"
13641409
if csvIsRequeued {
1365-
condition.Reason = "CopiedCSVsFound"
1366-
condition.Message = "Copied CSVs are disabled and at least one copied CSV was found for an operator installed in AllNamespace mode"
1410+
condition.Message = "Copied CSVs are disabled and at least one unexpected copied CSV was found for an operator installed in AllNamespace mode"
13671411
return condition
13681412
}
13691413

13701414
condition.Status = metav1.ConditionTrue
1371-
condition.Reason = "NoCopiedCSVsFound"
1372-
condition.Message = "Copied CSVs are disabled and none were found for operators installed in AllNamespace mode"
1415+
condition.Message = "Copied CSVs are disabled and no unexpected copied CSVs were found for operators installed in AllNamespace mode"
13731416

13741417
return condition
13751418
}
@@ -1444,7 +1487,24 @@ func (a *Operator) syncCopyCSV(obj interface{}) (syncError error) {
14441487
return err
14451488
}
14461489

1490+
// Ensure that the Copied CSVs exist in the protected namespaces.
1491+
protectedNamespaces := []string{}
1492+
for ns := range a.protectedCopiedCSVNamespaces {
1493+
if ns == clusterServiceVersion.GetNamespace() {
1494+
continue
1495+
}
1496+
protectedNamespaces = append(protectedNamespaces, ns)
1497+
}
1498+
1499+
if err := a.ensureCSVsInNamespaces(clusterServiceVersion, operatorGroup, NewNamespaceSet(protectedNamespaces)); err != nil {
1500+
return err
1501+
}
1502+
1503+
// Delete Copied CSVs in namespaces that are not protected.
14471504
for _, copiedCSV := range copiedCSVs {
1505+
if _, ok := a.protectedCopiedCSVNamespaces[copiedCSV.Namespace]; ok {
1506+
continue
1507+
}
14481508
err := a.client.OperatorsV1alpha1().ClusterServiceVersions(copiedCSV.Namespace).Delete(context.TODO(), copiedCSV.Name, metav1.DeleteOptions{})
14491509
if err != nil && !apierrors.IsNotFound(err) {
14501510
return err

‎test/e2e/disabling_copied_csv_e2e_test.go

+50-5
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ package e2e
33
import (
44
"context"
55
"fmt"
6+
"strings"
67

78
. "github.com/onsi/ginkgo/v2"
89
. "github.com/onsi/gomega"
910
operatorsv1 "github.com/operator-framework/api/pkg/operators/v1"
1011
operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
1112
"github.com/operator-framework/operator-lifecycle-manager/test/e2e/ctx"
13+
appsv1 "k8s.io/api/apps/v1"
1214
corev1 "k8s.io/api/core/v1"
1315
"k8s.io/apimachinery/pkg/api/meta"
1416
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -19,11 +21,17 @@ import (
1921
"sigs.k8s.io/controller-runtime/pkg/client"
2022
)
2123

24+
const (
25+
olmDeploymentName = "olm-operator"
26+
protectedCopiedCSVNamespacesRuntimeFlag = "--protectedCopiedCSVNamespaces"
27+
)
28+
2229
var _ = Describe("Disabling copied CSVs", func() {
2330
var (
2431
ns corev1.Namespace
2532
csv operatorsv1alpha1.ClusterServiceVersion
2633
nonTerminatingNamespaceSelector = fields.ParseSelectorOrDie("status.phase!=Terminating")
34+
protectedCopiedCSVNamespaces = map[string]struct{}{}
2735
)
2836

2937
BeforeEach(func() {
@@ -95,7 +103,6 @@ var _ = Describe("Disabling copied CSVs", func() {
95103
})
96104

97105
When("Copied CSVs are disabled", func() {
98-
99106
BeforeEach(func() {
100107
Eventually(func() error {
101108
var olmConfig operatorsv1.OLMConfig
@@ -122,6 +129,10 @@ var _ = Describe("Disabling copied CSVs", func() {
122129

123130
return nil
124131
}).Should(Succeed())
132+
133+
Eventually(func() error {
134+
return setProtectedCopiedCSVNamespaces(protectedCopiedCSVNamespaces)
135+
}).Should(Succeed())
125136
})
126137

127138
It("should not have any copied CSVs", func() {
@@ -139,8 +150,14 @@ var _ = Describe("Disabling copied CSVs", func() {
139150
return err
140151
}
141152

142-
if numCSVs := len(copiedCSVs.Items); numCSVs != 0 {
143-
return fmt.Errorf("Found %d copied CSVs, should be 0", numCSVs)
153+
if numCSVs := len(copiedCSVs.Items); numCSVs != len(protectedCopiedCSVNamespaces) {
154+
return fmt.Errorf("Found %d copied CSVs, should be %d", numCSVs, len(protectedCopiedCSVNamespaces))
155+
}
156+
157+
for _, csv := range copiedCSVs.Items {
158+
if _, ok := protectedCopiedCSVNamespaces[csv.GetNamespace()]; !ok {
159+
return fmt.Errorf("copied CSV %s/%s should not exist in the given namespace", csv.GetNamespace(), csv.GetName())
160+
}
144161
}
145162
return nil
146163
}).Should(Succeed())
@@ -159,8 +176,8 @@ var _ = Describe("Disabling copied CSVs", func() {
159176
}
160177

161178
expectedCondition := metav1.Condition{
162-
Reason: "NoCopiedCSVsFound",
163-
Message: "Copied CSVs are disabled and none were found for operators installed in AllNamespace mode",
179+
Reason: "CopiedCSVsDisabled",
180+
Message: "Copied CSVs are disabled and no unexpected copied CSVs were found for operators installed in AllNamespace mode",
164181
Status: metav1.ConditionTrue,
165182
}
166183

@@ -260,3 +277,31 @@ var _ = Describe("Disabling copied CSVs", func() {
260277
})
261278
})
262279
})
280+
281+
func setProtectedCopiedCSVNamespaces(protectedCopiedCSVNamespaces map[string]struct{}) error {
282+
var olmDeployment appsv1.Deployment
283+
if err := ctx.Ctx().Client().Get(context.TODO(), apitypes.NamespacedName{Name: olmDeploymentName, Namespace: operatorNamespace}, &olmDeployment); err != nil {
284+
return err
285+
}
286+
287+
if protectedNamespaceArgument := getRuntimeFlagValue(&olmDeployment, olmDeploymentName, protectedCopiedCSVNamespacesRuntimeFlag); protectedNamespaceArgument != "" {
288+
for _, namespace := range strings.Split(protectedNamespaceArgument, ",") {
289+
protectedCopiedCSVNamespaces[namespace] = struct{}{}
290+
}
291+
}
292+
293+
return nil
294+
}
295+
296+
func getRuntimeFlagValue(deployment *appsv1.Deployment, containerName string, runtimeFlag string) string {
297+
for _, container := range deployment.Spec.Template.Spec.Containers {
298+
if container.Name == containerName {
299+
for i := range container.Args {
300+
if container.Args[i] == runtimeFlag && len(container.Args) > i+1 {
301+
return container.Args[i+1]
302+
}
303+
}
304+
}
305+
}
306+
return ""
307+
}

0 commit comments

Comments
 (0)
Please sign in to comment.