Skip to content

Commit 8b2b6eb

Browse files
dhaiducekopenshift-merge-bot[bot]
authored andcommitted
Add recordDiff to policy generator
ref: https://issues.redhat.com/browse/ACM-9088 Signed-off-by: Dale Haiducek <[email protected]>
1 parent 4bf2b47 commit 8b2b6eb

File tree

6 files changed

+108
-60
lines changed

6 files changed

+108
-60
lines changed

docs/policygenerator-reference.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ policyDefaults:
160160
# the responsibility of the administrator to ensure the placement rule exists. Use of this setting will prevent a
161161
# placement rule from being generated, but the placement binding will still be created.
162162
placementRuleName: ""
163+
# Optional. Whether (and where) to record the diff between the policy and objects on the cluster. Defaults to an empty
164+
# string, which is equivalent to "None".
165+
recordDiff: ""
163166
# Optional. The remediation action ("inform" or "enforce") for each configuration policy. This defaults to "inform".
164167
remediationAction: "inform"
165168
# Optional. The severity of the policy violation. This defaults to "low".
@@ -238,6 +241,8 @@ policies:
238241
# Optional. (See policyDefaults.remediationAction for description.)
239242
# Cannot be specified when policyDefaults.consolidateManifests is set to true.
240243
remediationAction: ""
244+
# Optional. (See policyDefaults.recordDiff for description.)
245+
recordDiff: ""
241246
# Optional. (See policyDefaults.severity for description.)
242247
# Cannot be specified when policyDefaults.consolidateManifests is set to true.
243248
severity: "low"
@@ -308,6 +313,8 @@ policies:
308313
placement: {}
309314
# Optional. (See policyDefaults.remediationAction for description.)
310315
remediationAction: ""
316+
# Optional. (See policyDefaults.recordDiff for description.)
317+
recordDiff: ""
311318
# Optional. (See policyDefaults.severity for description.)
312319
severity: "low"
313320
# Optional. (See policyDefaults.standards for description.)

internal/plugin.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -563,11 +563,15 @@ func (p *Plugin) applyDefaults(unmarshaledConfig map[string]interface{}) {
563563
policy.Description = p.PolicyDefaults.Description
564564
}
565565

566+
if policy.RecordDiff == "" {
567+
policy.RecordDiff = p.PolicyDefaults.RecordDiff
568+
}
569+
566570
if policy.ComplianceType == "" {
567571
policy.ComplianceType = p.PolicyDefaults.ComplianceType
568572
}
569573

570-
if policy.MetadataComplianceType == "" && p.PolicyDefaults.MetadataComplianceType != "" {
574+
if policy.MetadataComplianceType == "" {
571575
policy.MetadataComplianceType = p.PolicyDefaults.MetadataComplianceType
572576
}
573577

@@ -693,7 +697,7 @@ func (p *Plugin) applyDefaults(unmarshaledConfig map[string]interface{}) {
693697
manifest.ComplianceType = policy.ComplianceType
694698
}
695699

696-
if manifest.MetadataComplianceType == "" && policy.MetadataComplianceType != "" {
700+
if manifest.MetadataComplianceType == "" {
697701
manifest.MetadataComplianceType = policy.MetadataComplianceType
698702
}
699703

@@ -729,6 +733,10 @@ func (p *Plugin) applyDefaults(unmarshaledConfig map[string]interface{}) {
729733
manifest.Severity = policy.Severity
730734
}
731735

736+
if manifest.RecordDiff == "" {
737+
manifest.RecordDiff = policy.RecordDiff
738+
}
739+
732740
if isManifestFieldSet(unmarshaledConfig, i, j, "extraDependencies") {
733741
applyDefaultDependencyFields(manifest.ExtraDependencies, p.PolicyDefaults.Namespace)
734742
} else {

internal/plugin_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ func TestGenerate(t *testing.T) {
4242
p.PolicyDefaults.Placement.Name = "my-placement"
4343
p.PolicyDefaults.Namespace = "my-policies"
4444
p.PolicyDefaults.MetadataComplianceType = "musthave"
45+
p.PolicyDefaults.RecordDiff = "Log"
4546
p.PolicyDefaults.PruneObjectBehavior = "DeleteAll"
4647
patch := map[string]interface{}{
4748
"metadata": map[string]interface{}{
@@ -68,6 +69,7 @@ func TestGenerate(t *testing.T) {
6869
{
6970
ConfigurationPolicyOptions: types.ConfigurationPolicyOptions{
7071
MetadataComplianceType: "mustonlyhave",
72+
RecordDiff: "None",
7173
},
7274
Path: path.Join(tmpDir, "configmap.yaml"),
7375
},
@@ -117,6 +119,7 @@ spec:
117119
labels:
118120
chandler: bing
119121
name: my-configmap
122+
recordDiff: Log
120123
pruneObjectBehavior: None
121124
remediationAction: inform
122125
severity: low
@@ -151,6 +154,7 @@ spec:
151154
kind: ConfigMap
152155
metadata:
153156
name: my-configmap
157+
recordDiff: None
154158
pruneObjectBehavior: DeleteAll
155159
remediationAction: inform
156160
severity: low

internal/types/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ type ConfigurationPolicyOptions struct {
4343
EvaluationInterval EvaluationInterval `json:"evaluationInterval,omitempty" yaml:"evaluationInterval,omitempty"`
4444
NamespaceSelector NamespaceSelector `json:"namespaceSelector,omitempty" yaml:"namespaceSelector,omitempty"`
4545
PruneObjectBehavior string `json:"pruneObjectBehavior,omitempty" yaml:"pruneObjectBehavior,omitempty"`
46+
RecordDiff string `json:"recordDiff,omitempty" yaml:"recordDiff,omitempty"`
4647
}
4748

4849
type Manifest struct {

internal/utils.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ func getPolicyTemplates(policyConf *types.PolicyConfig) ([]map[string]interface{
171171
for i, manifestGroup := range manifestGroups {
172172
complianceType := policyConf.Manifests[i].ComplianceType
173173
metadataComplianceType := policyConf.Manifests[i].MetadataComplianceType
174+
recordDiff := policyConf.Manifests[i].RecordDiff
174175
ignorePending := policyConf.Manifests[i].IgnorePending
175176
extraDeps := policyConf.Manifests[i].ExtraDependencies
176177

@@ -218,6 +219,10 @@ func getPolicyTemplates(policyConf *types.PolicyConfig) ([]map[string]interface{
218219
objTemplate["metadataComplianceType"] = metadataComplianceType
219220
}
220221

222+
if recordDiff != "" {
223+
objTemplate["recordDiff"] = recordDiff
224+
}
225+
221226
if policyConf.ConsolidateManifests {
222227
// put all objTemplate with manifest into single consolidated objectTemplates
223228
objectTemplates = append(objectTemplates, objTemplate)

internal/utils_test.go

Lines changed: 81 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ data:
175175
ConfigurationPolicyOptions: types.ConfigurationPolicyOptions{
176176
ComplianceType: "musthave",
177177
MetadataComplianceType: "mustonlyhave",
178+
RecordDiff: "Log",
178179
},
179180
Path: manifestPath,
180181
},
@@ -186,6 +187,7 @@ data:
186187
ConfigurationPolicyOptions: types.ConfigurationPolicyOptions{
187188
ComplianceType: "mustnothave",
188189
MetadataComplianceType: "musthave",
190+
RecordDiff: "None",
189191
},
190192
Path: manifestPath,
191193
},
@@ -202,25 +204,29 @@ data:
202204
}
203205

204206
// Test both passing in individual files and a flat directory
205-
tests := []struct {
207+
tests := map[string]struct {
206208
ExpectedComplianceType string
207209
ExpectedMetadataComplianceType string
210+
ExpectedRecordDiff string
208211
Manifests []types.Manifest
209212
}{
210-
{
213+
"musthave compType/mustonlyhave metaCompType/Log recDiff": {
211214
ExpectedComplianceType: "musthave",
212215
ExpectedMetadataComplianceType: "mustonlyhave",
216+
ExpectedRecordDiff: "Log",
213217
Manifests: manifestFiles,
214218
},
215-
{
219+
"mustnothave compType/musthave metaCompType/None recDiff": {
216220
ExpectedComplianceType: "mustnothave",
217221
ExpectedMetadataComplianceType: "musthave",
222+
ExpectedRecordDiff: "None",
218223
Manifests: manifestFilesMustNotHave,
219224
},
220225
// The applyDefaults method would normally fill in ComplianceType on each manifest entry.
221-
{
226+
"musthave compType/empty metaCompType/empty recDiff": {
222227
ExpectedComplianceType: "musthave",
223228
ExpectedMetadataComplianceType: "",
229+
ExpectedRecordDiff: "",
224230
Manifests: []types.Manifest{{
225231
ConfigurationPolicyOptions: types.ConfigurationPolicyOptions{ComplianceType: "musthave"},
226232
Path: tmpDir,
@@ -230,74 +236,91 @@ data:
230236
// test ConsolidateManifests = true (default case)
231237
// policyTemplates will have only one policyTemplate
232238
// and two objTemplate under this policyTemplate
233-
for _, test := range tests {
234-
policyConf := types.PolicyConfig{
235-
PolicyOptions: types.PolicyOptions{
236-
ConsolidateManifests: true,
237-
},
238-
ConfigurationPolicyOptions: types.ConfigurationPolicyOptions{
239-
ComplianceType: "musthave",
240-
RemediationAction: "inform",
241-
Severity: "low",
242-
},
243-
Manifests: test.Manifests,
244-
Name: "policy-app-config",
245-
}
239+
for testName, test := range tests {
240+
test := test
246241

247-
policyTemplates, err := getPolicyTemplates(&policyConf)
248-
if err != nil {
249-
t.Fatalf("Failed to get the policy templates: %v", err)
250-
}
242+
t.Run(testName, func(t *testing.T) {
243+
t.Parallel()
244+
policyConf := types.PolicyConfig{
245+
PolicyOptions: types.PolicyOptions{
246+
ConsolidateManifests: true,
247+
},
248+
ConfigurationPolicyOptions: types.ConfigurationPolicyOptions{
249+
ComplianceType: "musthave",
250+
RemediationAction: "inform",
251+
Severity: "low",
252+
},
253+
Manifests: test.Manifests,
254+
Name: "policy-app-config",
255+
}
251256

252-
assertEqual(t, len(policyTemplates), 1)
257+
policyTemplates, err := getPolicyTemplates(&policyConf)
258+
if err != nil {
259+
t.Fatalf("Failed to get the policy templates: %v", err)
260+
}
253261

254-
policyTemplate := policyTemplates[0]
255-
objdef := policyTemplate["objectDefinition"].(map[string]interface{})
262+
assertEqual(t, len(policyTemplates), 1)
256263

257-
assertEqual(t, objdef["metadata"].(map[string]interface{})["name"].(string), "policy-app-config")
264+
policyTemplate := policyTemplates[0]
265+
objdef := policyTemplate["objectDefinition"].(map[string]interface{})
258266

259-
spec, ok := objdef["spec"].(map[string]interface{})
260-
if !ok {
261-
t.Fatal("The spec field is an invalid format")
262-
}
267+
assertEqual(t, objdef["metadata"].(map[string]interface{})["name"].(string), "policy-app-config")
263268

264-
assertEqual(t, spec["remediationAction"], "inform")
265-
assertEqual(t, spec["severity"], "low")
269+
spec, ok := objdef["spec"].(map[string]interface{})
270+
if !ok {
271+
t.Fatal("The spec field is an invalid format")
272+
}
266273

267-
objTemplates, ok := spec["object-templates"].([]map[string]interface{})
268-
if !ok {
269-
t.Fatal("The object-templates field is an invalid format")
270-
}
274+
assertEqual(t, spec["remediationAction"], "inform")
275+
assertEqual(t, spec["severity"], "low")
271276

272-
assertEqual(t, len(objTemplates), 2)
273-
assertEqual(t, objTemplates[0]["complianceType"], test.ExpectedComplianceType)
277+
objTemplates, ok := spec["object-templates"].([]map[string]interface{})
278+
if !ok {
279+
t.Fatal("The object-templates field is an invalid format")
280+
}
274281

275-
if test.ExpectedMetadataComplianceType != "" {
276-
assertEqual(t, objTemplates[0]["metadataComplianceType"], test.ExpectedMetadataComplianceType)
277-
} else {
278-
assertEqual(t, objTemplates[0]["metadataComplianceType"], nil)
279-
}
282+
assertEqual(t, len(objTemplates), 2)
283+
assertEqual(t, objTemplates[0]["complianceType"], test.ExpectedComplianceType)
280284

281-
kind1, ok := objTemplates[0]["objectDefinition"].(map[string]interface{})["kind"]
282-
if !ok {
283-
t.Fatal("The objectDefinition field is an invalid format")
284-
}
285+
if test.ExpectedMetadataComplianceType != "" {
286+
assertEqual(t, objTemplates[0]["metadataComplianceType"], test.ExpectedMetadataComplianceType)
287+
} else {
288+
assertEqual(t, objTemplates[0]["metadataComplianceType"], nil)
289+
}
285290

286-
assertEqual(t, kind1, "ConfigMap")
287-
assertEqual(t, objTemplates[1]["complianceType"], test.ExpectedComplianceType)
291+
if test.ExpectedRecordDiff != "" {
292+
assertEqual(t, objTemplates[0]["recordDiff"], test.ExpectedRecordDiff)
293+
} else {
294+
assertEqual(t, objTemplates[0]["recordDiff"], nil)
295+
}
288296

289-
if test.ExpectedMetadataComplianceType != "" {
290-
assertEqual(t, objTemplates[0]["metadataComplianceType"], test.ExpectedMetadataComplianceType)
291-
} else {
292-
assertEqual(t, objTemplates[0]["metadataComplianceType"], nil)
293-
}
297+
kind1, ok := objTemplates[0]["objectDefinition"].(map[string]interface{})["kind"]
298+
if !ok {
299+
t.Fatal("The objectDefinition field is an invalid format")
300+
}
294301

295-
kind2, ok := objTemplates[1]["objectDefinition"].(map[string]interface{})["kind"]
296-
if !ok {
297-
t.Fatal("The objectDefinition field is an invalid format")
298-
}
302+
assertEqual(t, kind1, "ConfigMap")
303+
assertEqual(t, objTemplates[1]["complianceType"], test.ExpectedComplianceType)
299304

300-
assertEqual(t, kind2, "ConfigMap")
305+
if test.ExpectedMetadataComplianceType != "" {
306+
assertEqual(t, objTemplates[1]["metadataComplianceType"], test.ExpectedMetadataComplianceType)
307+
} else {
308+
assertEqual(t, objTemplates[1]["metadataComplianceType"], nil)
309+
}
310+
311+
if test.ExpectedRecordDiff != "" {
312+
assertEqual(t, objTemplates[1]["recordDiff"], test.ExpectedRecordDiff)
313+
} else {
314+
assertEqual(t, objTemplates[1]["recordDiff"], nil)
315+
}
316+
317+
kind2, ok := objTemplates[1]["objectDefinition"].(map[string]interface{})["kind"]
318+
if !ok {
319+
t.Fatal("The objectDefinition field is an invalid format")
320+
}
321+
322+
assertEqual(t, kind2, "ConfigMap")
323+
})
301324
}
302325
}
303326

0 commit comments

Comments
 (0)