diff --git a/azuread/resource_group.go b/azuread/resource_group.go index 17565aac48..292ea9ef09 100644 --- a/azuread/resource_group.go +++ b/azuread/resource_group.go @@ -1,6 +1,7 @@ package azuread import ( + "context" "fmt" "log" @@ -68,6 +69,11 @@ func resourceGroup() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "prevent_duplicate_names": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, }, } } @@ -78,6 +84,13 @@ func resourceGroupCreate(d *schema.ResourceData, meta interface{}) error { name := d.Get("name").(string) + if d.Get("prevent_duplicate_names").(bool) { + err := aadGroupCheckNameAvailability(client, ctx, name) + if err != nil { + return err + } + } + properties := graphrbac.GroupCreateParameters{ DisplayName: &name, MailEnabled: p.Bool(false), // we're defaulting to false, as the API currently only supports the creation of non-mail enabled security groups. @@ -168,6 +181,10 @@ func resourceGroupRead(d *schema.ResourceData, meta interface{}) error { } d.Set("owners", owners) + if preventDuplicates := d.Get("prevent_duplicate_names").(bool); !preventDuplicates { + d.Set("prevent_duplicate_names", false) + } + return nil } @@ -238,3 +255,31 @@ func resourceGroupDelete(d *schema.ResourceData, meta interface{}) error { return nil } + +func aadGroupFindByName(client graphrbac.GroupsClient, ctx context.Context, name string) (*graphrbac.ADGroup, error) { + nameFilter := fmt.Sprintf("displayName eq '%s'", name) + resp, err := client.List(ctx, nameFilter) + + if err != nil { + return nil, fmt.Errorf("unable to list Groups with filter %q: %+v", nameFilter, err) + } + + for _, group := range resp.Values() { + if *group.DisplayName == name { + return &group, nil + } + } + + return nil, nil +} + +func aadGroupCheckNameAvailability(client graphrbac.GroupsClient, ctx context.Context, name string) error { + existingGroup, err := aadGroupFindByName(client, ctx, name) + if err != nil { + return err + } + if existingGroup != nil { + return fmt.Errorf("Existing Azure Active Directory Group with name %q (ObjID: %q) was found and `prevent_duplicate_names` was specified", name, *existingGroup.ObjectID) + } + return nil +} diff --git a/azuread/resource_group_test.go b/azuread/resource_group_test.go index 83cb8f58b0..32a262bf4f 100644 --- a/azuread/resource_group_test.go +++ b/azuread/resource_group_test.go @@ -2,6 +2,7 @@ package azuread import ( "fmt" + "regexp" "testing" "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" @@ -286,6 +287,22 @@ func TestAccAzureADGroup_ownersUpdate(t *testing.T) { }) } +func TestAccAzureADGroup_preventDuplicateNames(t *testing.T) { + ri := tf.AccRandTimeInt() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckADApplicationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureADGroup_duplicateName(ri), + ExpectError: regexp.MustCompile("Existing Azure Active Directory Group .+ was found"), + }, + }, + }) +} + func testCheckAzureADGroupExists(name string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[name] @@ -503,3 +520,14 @@ resource "azuread_group" "test" { } `, id) } + +func testAccAzureADGroup_duplicateName(id int) string { + return fmt.Sprintf(` +%s + +resource "azuread_group" "duplicate" { + name = azuread_group.test.name + prevent_duplicate_names = true +} +`, testAccAzureADGroup_basic(id)) +} diff --git a/website/docs/r/group.markdown b/website/docs/r/group.markdown index df80da31fa..2553c6df6c 100644 --- a/website/docs/r/group.markdown +++ b/website/docs/r/group.markdown @@ -46,6 +46,7 @@ The following arguments are supported: * `description` - (Optional) The description for the Group. Changing this forces a new resource to be created. * `members` (Optional) A set of members who should be present in this Group. Supported Object types are Users, Groups or Service Principals. * `owners` (Optional) A set of owners who own this Group. Supported Object types are Users or Service Principals. +* `prevent_duplicate_names` - (Optional) If `true`, will return an error when an existing Application is found with the same name. Defaults to `false`. -> **NOTE:** Group names are not unique within Azure Active Directory.