in deployment/hierarchy.go [179:314]
func (h *Hierarchy) addManagementGroup(ctx context.Context, req managementGroupAddRequest) (*HierarchyManagementGroup, error) {
if req.parentId == "" {
return nil, fmt.Errorf("Hierarchy.AddManagementGroup: parent management group not specified for `%s`", req.id)
}
h.mu.Lock()
defer h.mu.Unlock()
if _, exists := h.mgs[req.id]; exists {
return nil, fmt.Errorf("Hierarchy.AddManagementGroup: management group %s already exists", req.id)
}
mg := newManagementGroup()
mg.id = req.id
mg.displayName = req.displayName
mg.exists = req.exists
mg.level = req.level
mg.children = mapset.NewSet[*HierarchyManagementGroup]()
mg.location = req.location
if req.parentIsExternal {
if _, ok := h.mgs[req.parentId]; ok {
return nil, fmt.Errorf("Hierarchy.AddManagementGroup: external parent management group set, but already exists %s", req.parentId)
}
mg.parentExternal = to.Ptr(req.parentId)
}
if !req.parentIsExternal {
parentMg, ok := h.mgs[req.parentId]
if !ok {
return nil, fmt.Errorf("Hierarchy.AddManagementGroup: parent management group not found %s", req.parentId)
}
mg.parent = parentMg
h.mgs[req.parentId].children.Add(mg)
}
// Get the policy definitions and policy set definitions referenced by the policy assignments.
assignedPolicyDefinitionIds := mapset.NewThreadUnsafeSet[string]()
// Combine all assignments form all supplied archetypes into a single set
allPolicyAssignments := mapset.NewThreadUnsafeSet[string]()
for _, archetype := range req.archetypes {
allPolicyAssignments = allPolicyAssignments.Union(archetype.PolicyAssignments)
}
for pa := range allPolicyAssignments.Iter() {
polAssign := h.alzlib.PolicyAssignment(pa)
if polAssign == nil {
return nil, fmt.Errorf("Hierarchy.AddManagementGroup: policy assignment `%s` referenced in management group `%s` does not exist in the library", pa, req.id)
}
referencedResourceId, err := polAssign.ReferencedPolicyDefinitionResourceId()
if err != nil {
return nil, fmt.Errorf("Hierarchy.AddManagementGroup: error getting referenced policy definition resource ID for policy assignment `%s` in management group `%s`: %w", pa, req.id, err)
}
assignedPolicyDefinitionIds.Add(referencedResourceId.String())
}
if err := h.alzlib.GetDefinitionsFromAzure(ctx, assignedPolicyDefinitionIds.ToSlice()); err != nil {
return nil, fmt.Errorf("Hierarchy.AddManagementGroup: adding mg `%s` error getting policy definitions from Azure: %w", req.id, err)
}
// Now that we are sure that we have all the definitions in the library,
// make copies of the archetype resources for modification in the Deployment management group.
// Copmbine all policy definitions form all supplied archetypes into a single set
allPolicyDefinitions := mapset.NewThreadUnsafeSet[string]()
for _, archetype := range req.archetypes {
allPolicyDefinitions = allPolicyDefinitions.Union(archetype.PolicyDefinitions)
}
for name := range allPolicyDefinitions.Iter() {
newDef := h.alzlib.PolicyDefinition(name)
if newDef == nil {
return nil, fmt.Errorf("Hierarchy.AddManagementGroup: policy definition `%s` in management group `%s` does not exist in the library", name, req.id)
}
mg.policyDefinitions[name] = newDef
}
// Combine all policy set definitions form all supplied archetypes into a single set
allPolicySetDefinitions := mapset.NewThreadUnsafeSet[string]()
for _, archetype := range req.archetypes {
allPolicySetDefinitions = allPolicySetDefinitions.Union(archetype.PolicySetDefinitions)
}
for name := range allPolicySetDefinitions.Iter() {
newSetDef := h.alzlib.PolicySetDefinition(name)
if newSetDef == nil {
return nil, fmt.Errorf("Hierarchy.AddManagementGroup(): policy set definition `%s` in management group `%s` does not exist in the library", name, req.id)
}
mg.policySetDefinitions[name] = newSetDef
}
// Now that the policy definitions and policy set definitions have been copied, we can add the policy assignments
for name := range allPolicyAssignments.Iter() {
newpolassign := h.alzlib.PolicyAssignment(name)
if newpolassign == nil {
return nil, fmt.Errorf("Hierarchy.AddManagementGroup(): policy assignment `%s` in management group `%s` does not exist in the library", name, req.id)
}
// Check if the referenced policy is a set and if its parameters match the parameters in the policy definitions
refPdId, _ := newpolassign.ReferencedPolicyDefinitionResourceId()
if refPdId.ResourceType.Type == "policySetDefinitions" {
psd := h.alzlib.PolicySetDefinition(refPdId.Name)
rfs := psd.PolicyDefinitionReferences()
for _, rf := range rfs {
resId, _ := arm.ParseResourceID(*rf.PolicyDefinitionID)
pd := h.alzlib.PolicyDefinition(resId.Name)
if pd == nil {
return nil, fmt.Errorf("Hierarchy.AddManagementGroup(): policy definition `%s` in policy set definition `%s` in management group `%s` does not exist in the library", resId.Name, refPdId.Name, req.id)
}
for param := range rf.Parameters {
if pd.Parameter(param) == nil {
return nil, fmt.Errorf("Hierarchy.AddManagementGroup(): parameter `%s` in policy set definition `%s` does not match a parameter in referenced definition `%s` in management group `%s`", param, *psd.Name, *pd.Name, req.id)
}
}
}
}
mg.policyAssignments[name] = newpolassign
}
// Combine all role definitions form all supplied archetypes into a single set
allRoleDefinitions := mapset.NewThreadUnsafeSet[string]()
for _, archetype := range req.archetypes {
allRoleDefinitions = allRoleDefinitions.Union(archetype.RoleDefinitions)
}
for name := range allRoleDefinitions.Iter() {
newroledef := h.alzlib.RoleDefinition(name)
if newroledef == nil {
return nil, fmt.Errorf("Hierarchy.AddManagementGroup(): role definition `%s` in management group `%s` does not exist in the library", name, req.id)
}
mg.roleDefinitions[name] = newroledef
}
// set the hierarchy on the management group.
mg.hierarchy = h
// add the management group to the deployment.
h.mgs[req.id] = mg
// run Update to change all refs, etc.
if err := h.mgs[req.id].update(); err != nil {
return nil, fmt.Errorf("Hierarchy.AddManagementGroup: adding `%s` error updating assets at scope %w", req.id, err)
}
return mg, nil
}