Skip to content

Commit

Permalink
feat: add ModifyPolicyAssignment func and deprecate UpsertPolicyAssig…
Browse files Browse the repository at this point in the history
…nments
  • Loading branch information
matt-FFFFFF committed Mar 5, 2024
1 parent 1184c0f commit ed05ade
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 139 deletions.
95 changes: 26 additions & 69 deletions alzmanagementgroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package alzlib

import (
"context"
"encoding/json"
"errors"
"fmt"
Expand Down Expand Up @@ -299,84 +298,42 @@ func (alzmg *AlzManagementGroup) update(az *AlzLib, papv PolicyAssignmentsParame
return nil
}

// UpsertPolicyAssignments adds policy assignments to the management group.
// These can be net-new assignments, or amendments to existing assignments.
// ModifyPolicyAssignment modifies an existing policy assignment in the management group.
// It will deep merge the supplied assignments with the existing assignments.
// If the assignment already exists, its attributes will be updated, but not entirely replaced.
func (alzmg *AlzManagementGroup) UpsertPolicyAssignments(ctx context.Context, pas map[string]*armpolicy.Assignment, az *AlzLib) error {
papv := make(PolicyAssignmentsParameterValues)
defsToGet := mapset.NewSet[string]()

for name, pa := range pas {
if _, ok := alzmg.policyAssignments[name]; !ok {
alzmg.policyAssignments[name] = pa
continue
}
if pa.Properties == nil {
continue
}
if alzmg.policyAssignments[name].Properties == nil {
alzmg.policyAssignments[name].Properties = new(armpolicy.AssignmentProperties)
}

if pa.Properties.DisplayName != nil {
alzmg.policyAssignments[name].Properties.DisplayName = pa.Properties.DisplayName
}

if pa.Properties.Description != nil {
alzmg.policyAssignments[name].Properties.Description = pa.Properties.Description
}

if pa.Properties.Metadata != nil {
alzmg.policyAssignments[name].Properties.Metadata = pa.Properties.Metadata
}

// Update policy assignment parameter values map.
if pa.Properties.Parameters != nil && len(pa.Properties.Parameters) > 0 {
papv[name] = pa.Properties.Parameters
}

if pa.Properties.EnforcementMode != nil {
alzmg.policyAssignments[name].Properties.EnforcementMode = pa.Properties.EnforcementMode
}
func (alzmg *AlzManagementGroup) ModifyPolicyAssignment(
name string,
parameters map[string]*armpolicy.ParameterValuesValue,
enforcementMode *armpolicy.EnforcementMode,
nonComplianceMessages []*armpolicy.NonComplianceMessage,
identity *armpolicy.Identity,
) error {
if _, ok := alzmg.policyAssignments[name]; !ok {
return fmt.Errorf("policy assignment %s not found in management group %s", name, alzmg.name)
}

if pa.Properties.NonComplianceMessages != nil {
if alzmg.policyAssignments[name].Properties.NonComplianceMessages == nil {
alzmg.policyAssignments[name].Properties.NonComplianceMessages = make([]*armpolicy.NonComplianceMessage, len(pa.Properties.NonComplianceMessages))
}
alzmg.policyAssignments[name].Properties.NonComplianceMessages = pa.Properties.NonComplianceMessages
}
if alzmg.policyAssignments[name].Properties == nil {
return fmt.Errorf("properties for policy assignment %s in management group %s is nil", name, alzmg.name)
}

if pa.Properties.PolicyDefinitionID != nil {
alzmg.policyAssignments[name].Properties.PolicyDefinitionID = pa.Properties.PolicyDefinitionID
switch lastButOneSegment(*pa.Properties.PolicyDefinitionID) {
case "policyDefinitions":
if !az.PolicyDefinitionExists(lastSegment(*pa.Properties.PolicyDefinitionID)) {
defsToGet.Add(*pa.Properties.PolicyDefinitionID)
}
case "policySetDefinitions":
if !az.PolicySetDefinitionExists(lastSegment(*pa.Properties.PolicyDefinitionID)) {
defsToGet.Add(*pa.Properties.PolicyDefinitionID)
}
}
}
if alzmg.policyAssignments[name].Properties.Parameters == nil && len(parameters) > 0 {
alzmg.policyAssignments[name].Properties.Parameters = make(map[string]*armpolicy.ParameterValuesValue, len(parameters))
}

// fetch defs that don't exist
if defsToGet.Cardinality() > 0 {
if err := az.GetDefinitionsFromAzure(ctx, defsToGet.ToSlice()); err != nil {
return err
}
for k, v := range parameters {
alzmg.policyAssignments[name].Properties.Parameters[k] = v
}

// update the policy assignments
pd2mg := az.Deployment.policyDefinitionToMg()
psd2mg := az.Deployment.policySetDefinitionToMg()
if enforcementMode != nil {
alzmg.policyAssignments[name].Properties.EnforcementMode = enforcementMode
}

if err := modifyPolicyAssignments(alzmg, pd2mg, psd2mg, papv); err != nil {
return err
if nonComplianceMessages != nil {
alzmg.policyAssignments[name].Properties.NonComplianceMessages = nonComplianceMessages
}

if identity != nil {
alzmg.policyAssignments[name].Identity = identity
}
return nil
}

Expand Down
119 changes: 49 additions & 70 deletions alzmanagementgroup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -673,98 +673,77 @@ func TestModifyRoleDefinitions(t *testing.T) {
assert.Empty(t, alzmg.roleDefinitions)
}

func TestUpsertPolicyAssignments(t *testing.T) {
// Create a new AlzLib instance.
az := NewAlzLib()
az.policyDefinitions = map[string]*armpolicy.Definition{
"test-policy-definition": {},
func TestCopyMap(t *testing.T) {
// Create a new map.
m := map[string]*int{
"foo": to.Ptr(1),
"bar": to.Ptr(2),
"baz": to.Ptr(3),
}

// Create a new AlzManagementGroup instance.
// Copy the map.
m2 := copyMap[string, int](m)

// Verify that the original map and the copied map are equal.
assert.Equal(t, len(m), len(m2))
for k, v := range m {
assert.Equal(t, *v, m2[k])
}

// Modify the original map.
m["foo"] = to.Ptr(4)

// Verify that the original map and the copied map are no longer equal.
assert.NotEqual(t, m, m2)
}

func TestModifyPolicyAssignment(t *testing.T) {
// Create a new AlzManagementGroup instance
alzmg := &AlzManagementGroup{
policyAssignments: make(map[string]*armpolicy.Assignment),
}

// Create a new policy assignment to upsert.
// Add a policy assignment to the management group
pa := &armpolicy.Assignment{
Name: to.Ptr("test-policy-assignment"),
Type: to.Ptr("Microsoft.Authorization/policyAssignments"),

Identity: &armpolicy.Identity{Type: to.Ptr(armpolicy.ResourceIdentityTypeSystemAssigned)},
Properties: &armpolicy.AssignmentProperties{
PolicyDefinitionID: to.Ptr("/providers/Microsoft.Authorization/policyDefinitions/test-policy-definition"),
Parameters: map[string]*armpolicy.ParameterValuesValue{
"parameter1": {Value: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/my-rg"},
"parameter2": {Value: "value2"},
"parameter1": {Value: "value1"},
},
},
}
alzmg.policyAssignments["test-policy-assignment"] = pa

// Upsert the policy assignment.
err := alzmg.UpsertPolicyAssignments(context.Background(), map[string]*armpolicy.Assignment{"test-policy-assignment": pa}, az)
assert.NoError(t, err)

// Verify that the policy assignment was added to the management group.
assert.Equal(t, 1, len(alzmg.policyAssignments))
assert.Equal(t, pa, alzmg.policyAssignments["test-policy-assignment"])

// Update the policy assignment.
pa.Properties.Parameters["parameter1"].Value = "/subscriptions/11111111-1111-1111-1111-111111111111/resourceGroups/my-rg"
pa.Properties.Parameters["parameter2"].Value = "value3"

// Upsert the updated policy assignment.
err = alzmg.UpsertPolicyAssignments(context.Background(), map[string]*armpolicy.Assignment{"test-policy-assignment": pa}, az)
assert.NoError(t, err)

// Verify that the policy assignment was updated in the management group.
assert.Equal(t, 1, len(alzmg.policyAssignments))
assert.Equal(t, pa, alzmg.policyAssignments["test-policy-assignment"])

// Add a new policy assignment.
pa2 := &armpolicy.Assignment{
Name: to.Ptr("test-policy-assignment-2"),
// Define the expected modified policy assignment
expected := &armpolicy.Assignment{
Name: to.Ptr("test-policy-assignment"),
Type: to.Ptr("Microsoft.Authorization/policyAssignments"),

Identity: &armpolicy.Identity{Type: to.Ptr(armpolicy.ResourceIdentityTypeSystemAssigned)},
Properties: &armpolicy.AssignmentProperties{
PolicyDefinitionID: to.Ptr("/providers/Microsoft.Authorization/policyDefinitions/test-policy-definition-2"),
Parameters: map[string]*armpolicy.ParameterValuesValue{
"parameter1": {Value: "/subscriptions/22222222-2222-2222-2222-222222222222/resourceGroups/my-rg"},
"parameter2": {Value: "value4"},
"parameter1": {Value: "value1"},
"parameter2": {Value: "value2"},
},
EnforcementMode: to.Ptr(armpolicy.EnforcementModeDefault),
NonComplianceMessages: []*armpolicy.NonComplianceMessage{},
},
Identity: &armpolicy.Identity{Type: to.Ptr(armpolicy.ResourceIdentityTypeSystemAssigned)},
}

// Upsert the new policy assignment.
err = alzmg.UpsertPolicyAssignments(context.Background(), map[string]*armpolicy.Assignment{"test-policy-assignment-2": pa2}, az)
assert.NoError(t, err)

// Verify that the new policy assignment was added to the management group.
assert.Equal(t, 2, len(alzmg.policyAssignments))
assert.Equal(t, pa, alzmg.policyAssignments["test-policy-assignment"])
assert.Equal(t, pa2, alzmg.policyAssignments["test-policy-assignment-2"])
}

func TestCopyMap(t *testing.T) {
// Create a new map.
m := map[string]*int{
"foo": to.Ptr(1),
"bar": to.Ptr(2),
"baz": to.Ptr(3),
}

// Copy the map.
m2 := copyMap[string, int](m)

// Verify that the original map and the copied map are equal.
assert.Equal(t, len(m), len(m2))
for k, v := range m {
assert.Equal(t, *v, m2[k])
}
// Call the ModifyPolicyAssignment function
err := alzmg.ModifyPolicyAssignment(
"test-policy-assignment",
map[string]*armpolicy.ParameterValuesValue{
"parameter2": {Value: "value2"},
},
to.Ptr(armpolicy.EnforcementModeDefault),
[]*armpolicy.NonComplianceMessage{},
&armpolicy.Identity{Type: to.Ptr(armpolicy.ResourceIdentityTypeSystemAssigned)},
)

// Modify the original map.
m["foo"] = to.Ptr(4)
// Check for errors
assert.NoError(t, err)

// Verify that the original map and the copied map are no longer equal.
assert.NotEqual(t, m, m2)
// Check if the policy assignment was modified correctly
assert.Equal(t, expected, alzmg.policyAssignments["test-policy-assignment"])
}

0 comments on commit ed05ade

Please sign in to comment.