Skip to content

Commit 3b155d5

Browse files
mprahlopenshift-ci[bot]
authored andcommitted
Add support for setting the configuration policy annotations
This will allow users to disable policy templating on generated configuration policies. Relates: https://github.com/stolostron/backlog/issues/23078 Signed-off-by: mprahl <[email protected]>
1 parent b8c3e19 commit 3b155d5

File tree

6 files changed

+127
-29
lines changed

6 files changed

+127
-29
lines changed

docs/policygenerator-reference.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ policyDefaults:
1717
# annotation. This defaults to ["CM Configuration Management"].
1818
categories:
1919
- "CM Configuration Management"
20+
# Optional. Key-value pairs of annotations to set on generated configuration policies. For
21+
# example, to disable policy templates, you can set this to:
22+
# {"policy.open-cluster-management.io/disable-templates": "true"}. This defaults to {}.
23+
configurationPolicyAnnotations: {}
2024
# Optional. Array of controls to be used in the policy.open-cluster-management.io/controls
2125
# annotation. This defaults to ["CM-2 Baseline Configuration"].
2226
controls:
@@ -149,6 +153,8 @@ policies:
149153
# Optional. Determines the policy controller behavior when comparing the manifest to objects on
150154
# the cluster ("musthave", "mustonlyhave", or "mustnothave"). Defaults to "musthave".
151155
complianceType: "musthave"
156+
# Optional. (See policyDefaults.configurationPolicyAnnotations for description.)
157+
configurationPolicyAnnotations: {}
152158
# Optional. (See policyDefaults.metadataComplianceType for description.)
153159
metadataComplianceType: ""
154160
# Optional. (See policyDefaults.controls for description.)

internal/plugin.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,14 @@ func (p *Plugin) applyDefaults(unmarshaledConfig map[string]interface{}) {
399399
policy.Categories = p.PolicyDefaults.Categories
400400
}
401401

402+
if policy.ConfigurationPolicyAnnotations == nil {
403+
annotations := map[string]string{}
404+
for k, v := range p.PolicyDefaults.ConfigurationPolicyAnnotations {
405+
annotations[k] = v
406+
}
407+
policy.ConfigurationPolicyAnnotations = annotations
408+
}
409+
402410
if policy.Standards == nil {
403411
policy.Standards = p.PolicyDefaults.Standards
404412
}

internal/plugin_test.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2235,3 +2235,81 @@ func TestGenerateEvaluationInterval(t *testing.T) {
22352235
}
22362236
}
22372237
}
2238+
2239+
func TestCreatePolicyWithConfigPolicyAnnotations(t *testing.T) {
2240+
t.Parallel()
2241+
tmpDir := t.TempDir()
2242+
createConfigMap(t, tmpDir, "configmap.yaml")
2243+
2244+
tests := []struct {
2245+
name string
2246+
annotations map[string]string
2247+
}{
2248+
{name: "no-override", annotations: nil},
2249+
{
2250+
name: "override",
2251+
annotations: map[string]string{
2252+
"policy.open-cluster-management.io/disable-templates": "true",
2253+
},
2254+
},
2255+
{
2256+
name: "override-empty",
2257+
annotations: map[string]string{},
2258+
},
2259+
}
2260+
2261+
for _, test := range tests {
2262+
test := test
2263+
t.Run(test.name, func(t *testing.T) {
2264+
t.Parallel()
2265+
2266+
p := Plugin{}
2267+
p.PolicyDefaults.Namespace = "my-policies"
2268+
p.PolicyDefaults.ConfigurationPolicyAnnotations = map[string]string{"test-default-annotation": "default"}
2269+
policyConf := types.PolicyConfig{
2270+
Name: "policy-app-config", Manifests: []types.Manifest{
2271+
{Path: path.Join(tmpDir, "configmap.yaml")},
2272+
},
2273+
}
2274+
if test.annotations != nil {
2275+
policyConf.ConfigurationPolicyAnnotations = test.annotations
2276+
}
2277+
2278+
p.Policies = append(p.Policies, policyConf)
2279+
p.applyDefaults(map[string]interface{}{})
2280+
2281+
err := p.createPolicy(&p.Policies[0])
2282+
if err != nil {
2283+
t.Fatal(err.Error())
2284+
}
2285+
2286+
output := p.outputBuffer.Bytes()
2287+
policyManifests, err := unmarshalManifestBytes(output)
2288+
if err != nil {
2289+
t.Fatal(err.Error())
2290+
}
2291+
// nolint: forcetypeassert
2292+
policyTemplates := (*policyManifests)[0]["spec"].(map[string]interface{})["policy-templates"].([]interface{})
2293+
// nolint: forcetypeassert
2294+
configPolicy := policyTemplates[0].(map[string]interface{})["objectDefinition"].(map[string]interface{})
2295+
// nolint: forcetypeassert
2296+
metadata := configPolicy["metadata"].(map[string]interface{})
2297+
2298+
if test.annotations != nil && len(test.annotations) == 0 {
2299+
assertEqual(t, metadata["annotations"], nil)
2300+
} else {
2301+
annotations := map[string]string{}
2302+
for key, val := range metadata["annotations"].(map[string]interface{}) {
2303+
// nolint: forcetypeassert
2304+
annotations[key] = val.(string)
2305+
}
2306+
2307+
if test.annotations == nil {
2308+
assertReflectEqual(t, annotations, map[string]string{"test-default-annotation": "default"})
2309+
} else {
2310+
assertReflectEqual(t, annotations, test.annotations)
2311+
}
2312+
}
2313+
})
2314+
}
2315+
}

internal/types/types.go

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,19 @@ type PolicyConfig struct {
4141
Name string `json:"name,omitempty" yaml:"name,omitempty"`
4242
NamespaceSelector NamespaceSelector `json:"namespaceSelector,omitempty" yaml:"namespaceSelector,omitempty"`
4343
// This is named Placement so that eventually PlacementRules and Placements will be supported
44-
Placement PlacementConfig `json:"placement,omitempty" yaml:"placement,omitempty"`
45-
RemediationAction string `json:"remediationAction,omitempty" yaml:"remediationAction,omitempty"`
46-
Severity string `json:"severity,omitempty" yaml:"severity,omitempty"`
47-
Standards []string `json:"standards,omitempty" yaml:"standards,omitempty"`
48-
ConsolidateManifests bool `json:"consolidateManifests,omitempty" yaml:"consolidateManifests,omitempty"`
49-
Disabled bool `json:"disabled,omitempty" yaml:"disabled,omitempty"`
50-
InformGatekeeperPolicies bool `json:"informGatekeeperPolicies,omitempty" yaml:"informGatekeeperPolicies,omitempty"`
51-
InformKyvernoPolicies bool `json:"informKyvernoPolicies,omitempty" yaml:"informKyvernoPolicies,omitempty"`
52-
GeneratePlacementWhenInSet bool `json:"generatePlacementWhenInSet,omitempty" yaml:"generatePlacementWhenInSet,omitempty"`
53-
PolicySets []string `json:"policySets,omitempty" yaml:"policySets,omitempty"`
54-
EvaluationInterval EvaluationInterval `json:"evaluationInterval,omitempty" yaml:"evaluationInterval,omitempty"`
55-
PolicyAnnotations map[string]string `json:"policyAnnotations,omitempty" yaml:"policyAnnotations,omitempty"`
44+
Placement PlacementConfig `json:"placement,omitempty" yaml:"placement,omitempty"`
45+
RemediationAction string `json:"remediationAction,omitempty" yaml:"remediationAction,omitempty"`
46+
Severity string `json:"severity,omitempty" yaml:"severity,omitempty"`
47+
Standards []string `json:"standards,omitempty" yaml:"standards,omitempty"`
48+
ConsolidateManifests bool `json:"consolidateManifests,omitempty" yaml:"consolidateManifests,omitempty"`
49+
Disabled bool `json:"disabled,omitempty" yaml:"disabled,omitempty"`
50+
InformGatekeeperPolicies bool `json:"informGatekeeperPolicies,omitempty" yaml:"informGatekeeperPolicies,omitempty"`
51+
InformKyvernoPolicies bool `json:"informKyvernoPolicies,omitempty" yaml:"informKyvernoPolicies,omitempty"`
52+
GeneratePlacementWhenInSet bool `json:"generatePlacementWhenInSet,omitempty" yaml:"generatePlacementWhenInSet,omitempty"`
53+
PolicySets []string `json:"policySets,omitempty" yaml:"policySets,omitempty"`
54+
EvaluationInterval EvaluationInterval `json:"evaluationInterval,omitempty" yaml:"evaluationInterval,omitempty"`
55+
PolicyAnnotations map[string]string `json:"policyAnnotations,omitempty" yaml:"policyAnnotations,omitempty"`
56+
ConfigurationPolicyAnnotations map[string]string `json:"configurationPolicyAnnotations,omitempty" yaml:"configurationPolicyAnnotations,omitempty"`
5657
}
5758

5859
type PolicyDefaults struct {
@@ -63,18 +64,19 @@ type PolicyDefaults struct {
6364
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
6465
NamespaceSelector NamespaceSelector `json:"namespaceSelector,omitempty" yaml:"namespaceSelector,omitempty"`
6566
// This is named Placement so that eventually PlacementRules and Placements will be supported
66-
Placement PlacementConfig `json:"placement,omitempty" yaml:"placement,omitempty"`
67-
RemediationAction string `json:"remediationAction,omitempty" yaml:"remediationAction,omitempty"`
68-
Severity string `json:"severity,omitempty" yaml:"severity,omitempty"`
69-
Standards []string `json:"standards,omitempty" yaml:"standards,omitempty"`
70-
ConsolidateManifests bool `json:"consolidateManifests,omitempty" yaml:"consolidateManifests,omitempty"`
71-
Disabled bool `json:"disabled,omitempty" yaml:"disabled,omitempty"`
72-
InformGatekeeperPolicies bool `json:"informGatekeeperPolicies,omitempty" yaml:"informGatekeeperPolicies,omitempty"`
73-
InformKyvernoPolicies bool `json:"informKyvernoPolicies,omitempty" yaml:"informKyvernoPolicies,omitempty"`
74-
GeneratePlacementWhenInSet bool `json:"generatePlacementWhenInSet,omitempty" yaml:"generatePlacementWhenInSet,omitempty"`
75-
PolicySets []string `json:"policySets,omitempty" yaml:"policySets,omitempty"`
76-
EvaluationInterval EvaluationInterval `json:"evaluationInterval,omitempty" yaml:"evaluationInterval,omitempty"`
77-
PolicyAnnotations map[string]string `json:"policyAnnotations,omitempty" yaml:"policyAnnotations,omitempty"`
67+
Placement PlacementConfig `json:"placement,omitempty" yaml:"placement,omitempty"`
68+
RemediationAction string `json:"remediationAction,omitempty" yaml:"remediationAction,omitempty"`
69+
Severity string `json:"severity,omitempty" yaml:"severity,omitempty"`
70+
Standards []string `json:"standards,omitempty" yaml:"standards,omitempty"`
71+
ConsolidateManifests bool `json:"consolidateManifests,omitempty" yaml:"consolidateManifests,omitempty"`
72+
Disabled bool `json:"disabled,omitempty" yaml:"disabled,omitempty"`
73+
InformGatekeeperPolicies bool `json:"informGatekeeperPolicies,omitempty" yaml:"informGatekeeperPolicies,omitempty"`
74+
InformKyvernoPolicies bool `json:"informKyvernoPolicies,omitempty" yaml:"informKyvernoPolicies,omitempty"`
75+
GeneratePlacementWhenInSet bool `json:"generatePlacementWhenInSet,omitempty" yaml:"generatePlacementWhenInSet,omitempty"`
76+
PolicySets []string `json:"policySets,omitempty" yaml:"policySets,omitempty"`
77+
EvaluationInterval EvaluationInterval `json:"evaluationInterval,omitempty" yaml:"evaluationInterval,omitempty"`
78+
PolicyAnnotations map[string]string `json:"policyAnnotations,omitempty" yaml:"policyAnnotations,omitempty"`
79+
ConfigurationPolicyAnnotations map[string]string `json:"configurationPolicyAnnotations,omitempty" yaml:"configurationPolicyAnnotations,omitempty"`
7880
}
7981

8082
type PolicySetConfig struct {

internal/utils.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ func buildPolicyTemplate(
251251
"objectDefinition": {
252252
"apiVersion": policyAPIVersion,
253253
"kind": configPolicyKind,
254-
"metadata": map[string]string{
254+
"metadata": map[string]interface{}{
255255
"name": name,
256256
},
257257
"spec": map[string]interface{}{
@@ -262,6 +262,10 @@ func buildPolicyTemplate(
262262
},
263263
}
264264

265+
if len(policyConf.ConfigurationPolicyAnnotations) > 0 {
266+
policyTemplate["objectDefinition"]["metadata"].(map[string]interface{})["annotations"] = policyConf.ConfigurationPolicyAnnotations
267+
}
268+
265269
if evaluationInterval.Compliant != "" || evaluationInterval.NonCompliant != "" {
266270
evalInterval := map[string]interface{}{}
267271

internal/utils_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ data:
121121

122122
policyTemplate := policyTemplates[0]
123123
objdef := policyTemplate["objectDefinition"]
124-
assertEqual(t, objdef["metadata"].(map[string]string)["name"], "policy-app-config")
124+
assertEqual(t, objdef["metadata"].(map[string]interface{})["name"].(string), "policy-app-config")
125125
spec, ok := objdef["spec"].(map[string]interface{})
126126
if !ok {
127127
t.Fatal("The spec field is an invalid format")
@@ -248,7 +248,7 @@ data:
248248
if i > 0 {
249249
name += fmt.Sprintf("%d", i+1)
250250
}
251-
assertEqual(t, objdef["metadata"].(map[string]string)["name"], name)
251+
assertEqual(t, objdef["metadata"].(map[string]interface{})["name"].(string), name)
252252
spec, ok := objdef["spec"].(map[string]interface{})
253253
if !ok {
254254
t.Fatal("The spec field is an invalid format")
@@ -440,7 +440,7 @@ data:
440440

441441
policyTemplate := policyTemplates[0]
442442
objdef := policyTemplate["objectDefinition"]
443-
assertEqual(t, objdef["metadata"].(map[string]string)["name"], "policy-app-config")
443+
assertEqual(t, objdef["metadata"].(map[string]interface{})["name"].(string), "policy-app-config")
444444
spec, ok := objdef["spec"].(map[string]interface{})
445445
if !ok {
446446
t.Fatal("The spec field is an invalid format")
@@ -522,7 +522,7 @@ data:
522522

523523
policyTemplate := policyTemplates[0]
524524
objdef := policyTemplate["objectDefinition"]
525-
assertEqual(t, objdef["metadata"].(map[string]string)["name"], "policy-app-config")
525+
assertEqual(t, objdef["metadata"].(map[string]interface{})["name"].(string), "policy-app-config")
526526
spec, ok := objdef["spec"].(map[string]interface{})
527527
if !ok {
528528
t.Fatal("The spec field is an invalid format")

0 commit comments

Comments
 (0)