Skip to content

Commit ae7f23c

Browse files
dhaiducekopenshift-merge-robot
authored andcommitted
Allow placement generation to be shut off
When Policies are generated separately from PolicySets, it may be desirable to only generate the Policies and not the placement manifests. Signed-off-by: Dale Haiducek <[email protected]>
1 parent f1a75cf commit ae7f23c

File tree

5 files changed

+191
-7
lines changed

5 files changed

+191
-7
lines changed

docs/policygenerator-reference.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,10 @@ policyDefaults:
152152
# generated for the policy since one is generated for the set. Set policies[*].generatePlacementWhenInSet
153153
# or policyDefaults.generatePlacementWhenInSet to override.
154154
policySets: []
155+
# Optional. Whether to generate placement manifests for policies. Placement generation occurs except when policies are
156+
# part of a policy set. Use this setting to turn off placement generation for policies not in policy sets. This
157+
# defaults to "true".
158+
generatePolicyPlacement: true
155159
# Optional. When a policy is part of a policy set, by default the generator will not generate the placement
156160
# for this policy since a placement is generated for the policy set. If a placement should still be generated,
157161
# set it to "true" so that the policy will be deployed with both policy placement and policy set placement.

internal/plugin.go

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,10 @@ func (p *Plugin) Generate() ([]byte, error) {
142142
plcNameToPolicyAndSetIdxs := map[string]map[string][]int{}
143143

144144
for i := range p.Policies {
145-
// only generate placement when GeneratePlacementWhenInSet equals to true or policy is not
146-
// part of any policy sets
147-
if p.Policies[i].GeneratePlacementWhenInSet || len(p.Policies[i].PolicySets) == 0 {
145+
// only generate placement when GeneratePlacementWhenInSet equals to true, GeneratePlacement is true,
146+
// or policy is not part of any policy sets
147+
if p.Policies[i].GeneratePlacementWhenInSet ||
148+
(p.Policies[i].GeneratePolicyPlacement && len(p.Policies[i].PolicySets) == 0) {
148149
plcName, err := p.createPlacement(&p.Policies[i].Placement, p.Policies[i].Name)
149150
if err != nil {
150151
return nil, err
@@ -429,6 +430,14 @@ func (p *Plugin) applyDefaults(unmarshaledConfig map[string]interface{}) {
429430
p.PolicyDefaults.Standards = defaults.Standards
430431
}
431432

433+
// GeneratePolicyPlacement defaults to true unless explicitly set in the config.
434+
gppValue, setGpp := getDefaultBool(unmarshaledConfig, "generatePolicyPlacement")
435+
if setGpp {
436+
p.PolicyDefaults.GeneratePolicyPlacement = gppValue
437+
} else {
438+
p.PolicyDefaults.GeneratePolicyPlacement = true
439+
}
440+
432441
// Generate temporary sets to later merge the policy sets declared in p.Policies[*] and p.PolicySets
433442
plcsetToPlc := make(map[string]map[string]bool)
434443
plcToPlcset := make(map[string]map[string]bool)
@@ -516,10 +525,18 @@ func (p *Plugin) applyDefaults(unmarshaledConfig map[string]interface{}) {
516525
policy.PolicySets = p.PolicyDefaults.PolicySets
517526
}
518527

519-
// GeneratePlacementWhenInSet default to false unless explicitly set in the config.
520-
gpValue, setGp := getPolicyBool(unmarshaledConfig, i, "generatePlacementWhenInSet")
521-
if setGp {
522-
policy.GeneratePlacementWhenInSet = gpValue
528+
// GeneratePolicyPlacement defaults to true unless explicitly set in the config.
529+
gppValue, setGpp := getPolicyBool(unmarshaledConfig, i, "generatePolicyPlacement")
530+
if setGpp {
531+
policy.GeneratePolicyPlacement = gppValue
532+
} else {
533+
policy.GeneratePolicyPlacement = p.PolicyDefaults.GeneratePolicyPlacement
534+
}
535+
536+
// GeneratePlacementWhenInSet defaults to false unless explicitly set in the config.
537+
gpsetValue, setGpset := getPolicyBool(unmarshaledConfig, i, "generatePlacementWhenInSet")
538+
if setGpset {
539+
policy.GeneratePlacementWhenInSet = gpsetValue
523540
} else {
524541
policy.GeneratePlacementWhenInSet = p.PolicyDefaults.GeneratePlacementWhenInSet
525542
}
@@ -824,6 +841,12 @@ func (p *Plugin) assertValidConfig() error {
824841
defaultPlacementOptions++
825842
}
826843

844+
if defaultPlacementOptions > 0 && !p.PolicyDefaults.GeneratePolicyPlacement {
845+
return errors.New(
846+
"policyDefaults must not specify a placement when generatePlacement is set to false",
847+
)
848+
}
849+
827850
if defaultPlacementOptions > 1 {
828851
return errors.New(
829852
"policyDefaults must specify only one of placement selector, placement path, or placement name",
@@ -1106,6 +1129,12 @@ func (p *Plugin) assertValidConfig() error {
11061129
policyPlacementOptions++
11071130
}
11081131

1132+
if policyPlacementOptions > 0 && !policy.GeneratePolicyPlacement {
1133+
return fmt.Errorf(
1134+
"policy %s must not specify a placement when generatePlacement is set to false", policy.Name,
1135+
)
1136+
}
1137+
11091138
if policyPlacementOptions > 1 {
11101139
return fmt.Errorf(
11111140
"policy %s must specify only one of placement selector, placement path, or placement name", policy.Name,

internal/plugin_config_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,74 @@ policies:
379379
assertEqual(t, err.Error(), expected)
380380
}
381381

382+
func TestConfigDefaultPlacementWithDisabledPlacement(t *testing.T) {
383+
t.Parallel()
384+
tmpDir := t.TempDir()
385+
createConfigMap(t, tmpDir, "configmap.yaml")
386+
config := fmt.Sprintf(`
387+
apiVersion: policy.open-cluster-management.io/v1
388+
kind: PolicyGenerator
389+
metadata:
390+
name: policy-generator-name
391+
policyDefaults:
392+
namespace: my-policies
393+
generatePolicyPlacement: false
394+
placement:
395+
clusterSelectors:
396+
cloud: red hat
397+
policies:
398+
- name: policy-app-config
399+
manifests:
400+
- path: %s
401+
`,
402+
path.Join(tmpDir, "configmap.yaml"),
403+
)
404+
p := Plugin{}
405+
406+
err := p.Config([]byte(config), tmpDir)
407+
if err == nil {
408+
t.Fatal("Expected an error but did not get one")
409+
}
410+
411+
expected := "policyDefaults must not specify " +
412+
"a placement when generatePlacement is set to false"
413+
assertEqual(t, err.Error(), expected)
414+
}
415+
416+
func TestConfigPlacementWithDisabledPlacement(t *testing.T) {
417+
t.Parallel()
418+
tmpDir := t.TempDir()
419+
createConfigMap(t, tmpDir, "configmap.yaml")
420+
config := fmt.Sprintf(`
421+
apiVersion: policy.open-cluster-management.io/v1
422+
kind: PolicyGenerator
423+
metadata:
424+
name: policy-generator-name
425+
policyDefaults:
426+
namespace: my-policies
427+
placement:
428+
clusterSelectors:
429+
cloud: red hat
430+
policies:
431+
- name: policy-app-config
432+
generatePolicyPlacement: false
433+
manifests:
434+
- path: %s
435+
`,
436+
path.Join(tmpDir, "configmap.yaml"),
437+
)
438+
p := Plugin{}
439+
440+
err := p.Config([]byte(config), tmpDir)
441+
if err == nil {
442+
t.Fatal("Expected an error but did not get one")
443+
}
444+
445+
expected := "policy policy-app-config must not specify " +
446+
"a placement when generatePlacement is set to false"
447+
assertEqual(t, err.Error(), expected)
448+
}
449+
382450
func TestConfigMultiplePlacementsClusterSelectorAndPlRPath(t *testing.T) {
383451
t.Parallel()
384452
tmpDir := t.TempDir()

internal/plugin_test.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,88 @@ policies:
291291
}
292292
}
293293

294+
func TestGeneratePolicyDisablePlacement(t *testing.T) {
295+
t.Parallel()
296+
tmpDir := t.TempDir()
297+
createConfigMap(t, tmpDir, "configmap.yaml")
298+
299+
p := Plugin{}
300+
var err error
301+
302+
p.baseDirectory, err = filepath.EvalSymlinks(tmpDir)
303+
if err != nil {
304+
t.Fatal(err.Error())
305+
}
306+
307+
p.PolicyDefaults.Namespace = "my-policies"
308+
p.PolicyDefaults.MetadataComplianceType = "musthave"
309+
policyConf := types.PolicyConfig{
310+
Name: "policy-app-config",
311+
Manifests: []types.Manifest{
312+
{
313+
Path: path.Join(tmpDir, "configmap.yaml"),
314+
},
315+
},
316+
}
317+
p.Policies = append(p.Policies, policyConf)
318+
p.applyDefaults(map[string]interface{}{
319+
"policyDefaults": map[string]interface{}{
320+
"generatePolicyPlacement": false,
321+
},
322+
})
323+
assertEqual(t, p.Policies[0].GeneratePolicyPlacement, false)
324+
// Default all policy ConsolidateManifests flags are set to true
325+
// unless explicitly set
326+
assertEqual(t, p.Policies[0].ConsolidateManifests, true)
327+
328+
if err := p.assertValidConfig(); err != nil {
329+
t.Fatal(err.Error())
330+
}
331+
332+
expected := `
333+
---
334+
apiVersion: policy.open-cluster-management.io/v1
335+
kind: Policy
336+
metadata:
337+
annotations:
338+
policy.open-cluster-management.io/categories: CM Configuration Management
339+
policy.open-cluster-management.io/controls: CM-2 Baseline Configuration
340+
policy.open-cluster-management.io/standards: NIST SP 800-53
341+
name: policy-app-config
342+
namespace: my-policies
343+
spec:
344+
disabled: false
345+
policy-templates:
346+
- objectDefinition:
347+
apiVersion: policy.open-cluster-management.io/v1
348+
kind: ConfigurationPolicy
349+
metadata:
350+
name: policy-app-config
351+
spec:
352+
object-templates:
353+
- complianceType: musthave
354+
metadataComplianceType: musthave
355+
objectDefinition:
356+
apiVersion: v1
357+
data:
358+
game.properties: enemies=potato
359+
kind: ConfigMap
360+
metadata:
361+
name: my-configmap
362+
remediationAction: inform
363+
severity: low
364+
remediationAction: inform
365+
`
366+
expected = strings.TrimPrefix(expected, "\n")
367+
368+
output, err := p.Generate()
369+
if err != nil {
370+
t.Fatal(err.Error())
371+
}
372+
373+
assertEqual(t, string(output), expected)
374+
}
375+
294376
func TestGeneratePolicyExistingPlacementRuleName(t *testing.T) {
295377
t.Parallel()
296378
tmpDir := t.TempDir()

internal/types/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type PolicyOptions struct {
2020
IgnorePending bool `json:"ignorePending,omitempty" yaml:"ignorePending,omitempty"`
2121
InformGatekeeperPolicies bool `json:"informGatekeeperPolicies,omitempty" yaml:"informGatekeeperPolicies,omitempty"`
2222
InformKyvernoPolicies bool `json:"informKyvernoPolicies,omitempty" yaml:"informKyvernoPolicies,omitempty"`
23+
GeneratePolicyPlacement bool `json:"generatePolicyPlacement,omitempty" yaml:"generatePolicyPlacement,omitempty"`
2324
GeneratePlacementWhenInSet bool `json:"generatePlacementWhenInSet,omitempty" yaml:"generatePlacementWhenInSet,omitempty"`
2425
PolicySets []string `json:"policySets,omitempty" yaml:"policySets,omitempty"`
2526
PolicyAnnotations map[string]string `json:"policyAnnotations,omitempty" yaml:"policyAnnotations,omitempty"`

0 commit comments

Comments
 (0)