func()

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
}