diff --git a/docs/data-sources/users.md b/docs/data-sources/users.md index b9ddab5915..9bbd0f22db 100644 --- a/docs/data-sources/users.md +++ b/docs/data-sources/users.md @@ -26,12 +26,13 @@ data "azuread_users" "users" { The following arguments are supported: -* `mail_nicknames` - (Optional) The email aliases of the users. * `ignore_missing` - (Optional) Ignore missing users and return users that were found. The data source will still fail if no users are found. Defaults to false. +* `mail_nicknames` - (Optional) The email aliases of the users. * `object_ids` - (Optional) The object IDs of the users. +* `return_all_users` - (Optional) When `true`, the data source will return all users. Cannot be used with `ignore_missing`. Defaults to false. * `user_principal_names` - (Optional) The user principal names (UPNs) of the users. -~> One of `user_principal_names`, `object_ids` or `mail_nicknames` must be specified. These _may_ be specified as an empty list, in which case no results will be returned. +~> Either `return_all_users`, or one of `user_principal_names`, `object_ids` or `mail_nicknames` must be specified. These _may_ be specified as an empty list, in which case no results will be returned. ## Attributes Reference diff --git a/internal/services/users/user_data_source_test.go b/internal/services/users/user_data_source_test.go index e88a2ede29..558e80f424 100644 --- a/internal/services/users/user_data_source_test.go +++ b/internal/services/users/user_data_source_test.go @@ -80,7 +80,7 @@ func (UserDataSource) testCheckFunc(data acceptance.TestData) resource.TestCheck check.That(data.ResourceName).Key("display_name").HasValue(fmt.Sprintf("acctestUser-%d-DisplayName", data.RandomInteger)), check.That(data.ResourceName).Key("given_name").HasValue(fmt.Sprintf("acctestUser-%d-GivenName", data.RandomInteger)), check.That(data.ResourceName).Key("job_title").HasValue(fmt.Sprintf("acctestUser-%d-Job", data.RandomInteger)), - //check.That(data.ResourceName).Key("mail").Exists(), // TODO only set for O365 domains + // check.That(data.ResourceName).Key("mail").Exists(), // TODO only set for O365 domains check.That(data.ResourceName).Key("mail_nickname").HasValue(fmt.Sprintf("acctestUser-%d-MailNickname", data.RandomInteger)), check.That(data.ResourceName).Key("mobile_phone").HasValue("(555) 555-5555"), check.That(data.ResourceName).Key("object_id").IsUuid(), diff --git a/internal/services/users/users_data_source.go b/internal/services/users/users_data_source.go index 9fa6d63c92..d1e0f40d6a 100644 --- a/internal/services/users/users_data_source.go +++ b/internal/services/users/users_data_source.go @@ -34,7 +34,7 @@ func usersData() *schema.Resource { Type: schema.TypeList, Optional: true, Computed: true, - ExactlyOneOf: []string{"object_ids", "user_principal_names", "mail_nicknames"}, + ExactlyOneOf: []string{"object_ids", "user_principal_names", "mail_nicknames", "return_all_users"}, Elem: &schema.Schema{ Type: schema.TypeString, ValidateDiagFunc: validate.NoEmptyStrings, @@ -46,7 +46,7 @@ func usersData() *schema.Resource { Type: schema.TypeList, Optional: true, Computed: true, - ExactlyOneOf: []string{"object_ids", "user_principal_names", "mail_nicknames"}, + ExactlyOneOf: []string{"object_ids", "user_principal_names", "mail_nicknames", "return_all_users"}, Elem: &schema.Schema{ Type: schema.TypeString, ValidateDiagFunc: validate.UUID, @@ -58,7 +58,7 @@ func usersData() *schema.Resource { Type: schema.TypeList, Optional: true, Computed: true, - ExactlyOneOf: []string{"object_ids", "user_principal_names", "mail_nicknames"}, + ExactlyOneOf: []string{"object_ids", "user_principal_names", "mail_nicknames", "return_all_users"}, Elem: &schema.Schema{ Type: schema.TypeString, ValidateDiagFunc: validate.NoEmptyStrings, @@ -66,10 +66,20 @@ func usersData() *schema.Resource { }, "ignore_missing": { - Description: "Ignore missing users and return users that were found. The data source will still fail if no users are found", - Type: schema.TypeBool, - Optional: true, - Default: false, + Description: "Ignore missing users and return users that were found. The data source will still fail if no users are found", + Type: schema.TypeBool, + Optional: true, + Default: false, + ConflictsWith: []string{"return_all_users"}, + }, + + "return_all_users": { + Description: "Fetch all users with no filter and return all that were found. The data source will still fail if no users are found.", + Type: schema.TypeBool, + Optional: true, + Default: false, + ConflictsWith: []string{"ignore_missing"}, + ExactlyOneOf: []string{"object_ids", "user_principal_names", "mail_nicknames", "return_all_users"}, }, "users": { @@ -151,8 +161,18 @@ func usersDataSourceRead(ctx context.Context, d *schema.ResourceData, meta inter var users []msgraph.User var expectedCount int ignoreMissing := d.Get("ignore_missing").(bool) + returnAllUsers := d.Get("return_all_users").(bool) - if upns, ok := d.Get("user_principal_names").([]interface{}); ok && len(upns) > 0 { + if returnAllUsers { + result, _, err := client.List(ctx, odata.Query{}) + if err != nil { + return tf.ErrorDiagF(err, "Could not retrieve users") + } + if result == nil { + return tf.ErrorDiagF(errors.New("API returned nil result"), "Bad API Response") + } + users = append(users, *result...) + } else if upns, ok := d.Get("user_principal_names").([]interface{}); ok && len(upns) > 0 { expectedCount = len(upns) for _, v := range upns { query := odata.Query{ @@ -223,7 +243,8 @@ func usersDataSourceRead(ctx context.Context, d *schema.ResourceData, meta inter } } - if !ignoreMissing && len(users) != expectedCount { + // Check that the right number of users were returned + if !returnAllUsers && !ignoreMissing && len(users) != expectedCount { return tf.ErrorDiagF(fmt.Errorf("Expected: %d, Actual: %d", expectedCount, len(users)), "Unexpected number of users returned") } diff --git a/internal/services/users/users_data_source_test.go b/internal/services/users/users_data_source_test.go index f22e4ee780..34ffdac80a 100644 --- a/internal/services/users/users_data_source_test.go +++ b/internal/services/users/users_data_source_test.go @@ -106,6 +106,20 @@ func TestAccUsersDataSource_noNames(t *testing.T) { }}) } +func TestAccUsersDataSource_returnAll(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azuread_users", "test") + + data.DataSourceTest(t, []resource.TestStep{{ + Config: UsersDataSource{}.returnAll(), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("user_principal_names.#").Exists(), + check.That(data.ResourceName).Key("object_ids.#").Exists(), + check.That(data.ResourceName).Key("mail_nicknames.#").Exists(), + check.That(data.ResourceName).Key("users.#").Exists(), + ), + }}) +} + func (UsersDataSource) byUserPrincipalNames(data acceptance.TestData) string { return fmt.Sprintf(` %[1]s @@ -192,3 +206,11 @@ data "azuread_users" "test" { } ` } + +func (UsersDataSource) returnAll() string { + return ` +data "azuread_users" "test" { + return_all_users = true +} +` +}