diff --git a/gitlab/data_source_gitlab_users.go b/gitlab/data_source_gitlab_users.go new file mode 100644 index 000000000..cb9a11af4 --- /dev/null +++ b/gitlab/data_source_gitlab_users.go @@ -0,0 +1,310 @@ +package gitlab + +import ( + "fmt" + "strconv" + "strings" + "time" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" + gitlab "github.com/xanzy/go-gitlab" +) + +func dataSourceGitlabUsers() *schema.Resource { + return &schema.Resource{ + Read: dataSourceGitlabUsersRead, + + Schema: map[string]*schema.Schema{ + "order_by": { + Type: schema.TypeString, + Optional: true, + Default: "id", + ValidateFunc: validation.StringInSlice([]string{"id", "name", + "username", "created_at", "updated_at"}, true), + }, + "sort": { + Type: schema.TypeString, + Optional: true, + Default: "desc", + ValidateFunc: validation.StringInSlice([]string{"desc", "asc"}, true), + }, + "search": { + Type: schema.TypeString, + Optional: true, + }, + "active": { + Type: schema.TypeBool, + Optional: true, + }, + "blocked": { + Type: schema.TypeBool, + Optional: true, + }, + "extern_uid": { + Type: schema.TypeString, + Optional: true, + }, + "extern_provider": { + Type: schema.TypeString, + Optional: true, + }, + "created_before": { + Type: schema.TypeString, + Optional: true, + }, + "created_after": { + Type: schema.TypeString, + Optional: true, + }, + "users": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeInt, + Computed: true, + }, + "username": { + Type: schema.TypeString, + Computed: true, + }, + "email": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "is_admin": { + Type: schema.TypeBool, + Computed: true, + }, + "can_create_group": { + Type: schema.TypeBool, + Computed: true, + }, + "can_create_project": { + Type: schema.TypeBool, + Computed: true, + }, + "projects_limit": { + Type: schema.TypeInt, + Computed: true, + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + }, + "state": { + Type: schema.TypeString, + Computed: true, + }, + "external": { + Type: schema.TypeBool, + Computed: true, + }, + "extern_uid": { + Type: schema.TypeString, + Computed: true, + }, + "organization": { + Type: schema.TypeString, + Computed: true, + }, + "two_factor_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "provider": { + Type: schema.TypeString, + Computed: true, + }, + "avatar_url": { + Type: schema.TypeString, + Computed: true, + }, + "bio": { + Type: schema.TypeString, + Computed: true, + }, + "location": { + Type: schema.TypeString, + Computed: true, + }, + "skype": { + Type: schema.TypeString, + Computed: true, + }, + "linkedin": { + Type: schema.TypeString, + Computed: true, + }, + "twitter": { + Type: schema.TypeString, + Computed: true, + }, + "website_url": { + Type: schema.TypeString, + Computed: true, + }, + "theme_id": { + Type: schema.TypeInt, + Computed: true, + }, + "color_scheme_id": { + Type: schema.TypeInt, + Computed: true, + }, + "last_sign_in_at": { + Type: schema.TypeString, + Computed: true, + }, + "current_sign_in_at": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceGitlabUsersRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*gitlab.Client) + + listUsersOptions, id, err := expandGitlabUsersOptions(d) + if err != nil { + return err + } + users, _, err := client.Users.ListUsers(listUsersOptions) + + if err != nil { + return err + } + + d.Set("users", flattenGitlabUsers(users)) + d.SetId(fmt.Sprintf("%d", id)) + + return nil +} + +func flattenGitlabUsers(users []*gitlab.User) []interface{} { + usersList := []interface{}{} + + for _, user := range users { + values := map[string]interface{}{ + "id": user.ID, + "username": user.Username, + "email": user.Email, + "name": user.Name, + "is_admin": user.IsAdmin, + "can_create_group": user.CanCreateGroup, + "can_create_project": user.CanCreateProject, + "projects_limit": user.ProjectsLimit, + "state": user.State, + "external": user.External, + "extern_uid": user.ExternUID, + "provider": user.Provider, + "two_factor_enabled": user.TwoFactorEnabled, + "avatar_url": user.AvatarURL, + "bio": user.Bio, + "location": user.Location, + "skype": user.Skype, + "linkedin": user.Linkedin, + "twitter": user.Twitter, + "website_url": user.WebsiteURL, + "organization": user.Organization, + "theme_id": user.ThemeID, + "color_scheme_id": user.ColorSchemeID, + } + + if user.CreatedAt != nil { + values["created_at"] = user.CreatedAt.String() + } + if user.LastSignInAt != nil { + values["last_sign_in_at"] = user.LastSignInAt.String() + } + if user.CurrentSignInAt != nil { + values["current_sign_in_at"] = user.CurrentSignInAt.String() + } + + usersList = append(usersList, values) + } + + return usersList +} + +func expandGitlabUsersOptions(d *schema.ResourceData) (*gitlab.ListUsersOptions, int, error) { + listUsersOptions := &gitlab.ListUsersOptions{} + var optionsHash strings.Builder + + if data, ok := d.GetOk("order_by"); ok { + orderBy := data.(string) + listUsersOptions.OrderBy = &orderBy + optionsHash.WriteString(orderBy) + } + optionsHash.WriteString(",") + if data, ok := d.GetOk("sort"); ok { + sort := data.(string) + listUsersOptions.Sort = &sort + optionsHash.WriteString(sort) + } + optionsHash.WriteString(",") + if data, ok := d.GetOk("search"); ok { + search := data.(string) + listUsersOptions.Search = &search + optionsHash.WriteString(search) + } + optionsHash.WriteString(",") + if data, ok := d.GetOk("active"); ok { + active := data.(bool) + listUsersOptions.Active = &active + optionsHash.WriteString(strconv.FormatBool(active)) + } + optionsHash.WriteString(",") + if data, ok := d.GetOk("blocked"); ok { + blocked := data.(bool) + listUsersOptions.Blocked = &blocked + optionsHash.WriteString(strconv.FormatBool(blocked)) + } + optionsHash.WriteString(",") + if data, ok := d.GetOk("extern_uid"); ok { + externalUID := data.(string) + listUsersOptions.ExternalUID = &externalUID + optionsHash.WriteString(externalUID) + } + optionsHash.WriteString(",") + if data, ok := d.GetOk("extern_provider"); ok { + provider := data.(string) + listUsersOptions.Provider = &provider + optionsHash.WriteString(provider) + } + optionsHash.WriteString(",") + if data, ok := d.GetOk("created_before"); ok { + createdBefore := data.(string) + date, err := time.Parse("2006-01-02", createdBefore) + if err != nil { + return nil, 0, fmt.Errorf("created_before must be in yyyy-mm-dd format") + } + listUsersOptions.CreatedBefore = &date + optionsHash.WriteString(createdBefore) + } + optionsHash.WriteString(",") + if data, ok := d.GetOk("created_after"); ok { + createdAfter := data.(string) + date, err := time.Parse("2006-01-02", createdAfter) + if err != nil { + return nil, 0, fmt.Errorf("created_after must be in yyyy-mm-dd format") + } + listUsersOptions.CreatedAfter = &date + optionsHash.WriteString(createdAfter) + } + + id := schema.HashString(optionsHash.String()) + + return listUsersOptions, id, nil +} diff --git a/gitlab/data_source_gitlab_users_test.go b/gitlab/data_source_gitlab_users_test.go new file mode 100644 index 000000000..8ae419c70 --- /dev/null +++ b/gitlab/data_source_gitlab_users_test.go @@ -0,0 +1,114 @@ +package gitlab + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccDataSourceGitlabUsers_basic(t *testing.T) { + rInt := acctest.RandInt() + rInt2 := acctest.RandInt() + user2 := fmt.Sprintf("user%d@test.test", rInt2) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceGitlabUsersConfig(rInt, rInt2), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("gitlab_user.foo", "name", "footest1"), + resource.TestCheckResourceAttr("gitlab_user.foo2", "name", "footest2"), + ), + }, + { + Config: testAccDataSourceGitlabUsersConfigSort(rInt, rInt2), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.gitlab_users.foo", "users.#", "2"), + resource.TestCheckResourceAttr("data.gitlab_users.foo", "users.0.email", user2), + resource.TestCheckResourceAttr("data.gitlab_users.foo", "users.0.projects_limit", "2"), + ), + }, + { + Config: testAccDataSourceGitlabUsersConfigSearch(rInt, rInt2), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.gitlab_users.foo", "users.#", "1"), + // resource.TestCheckResourceAttr("data.gitlab_users.foo", "users.0.email", user2), + ), + }, + }, + }) +} + +func testAccDataSourceGitlabUsersConfig(rInt int, rInt2 int) string { + return fmt.Sprintf(` +resource "gitlab_user" "foo" { + name = "footest1" + username = "listest%d" + password = "test%dtt" + email = "user%d@test.test" + projects_limit = 3 +} + +resource "gitlab_user" "foo2" { + name = "footest2" + username = "listest%d" + password = "test%dtt" + email = "user%d@test.test" + projects_limit = 2 +} + `, rInt, rInt, rInt, rInt2, rInt2, rInt2) +} + +func testAccDataSourceGitlabUsersConfigSort(rInt int, rInt2 int) string { + return fmt.Sprintf(` +resource "gitlab_user" "foo" { + name = "footest1" + username = "listest%d" + password = "test%dtt" + email = "user%d@test.test" + projects_limit = 3 +} + +resource "gitlab_user" "foo2" { + name = "footest2" + username = "listest%d" + password = "test%dtt" + email = "user%d@test.test" + projects_limit = 2 +} + +data "gitlab_users" "foo" { + sort = "desc" + search = "footest" + order_by = "name" +} + `, rInt, rInt, rInt, rInt2, rInt2, rInt2) +} + +func testAccDataSourceGitlabUsersConfigSearch(rInt int, rInt2 int) string { + return fmt.Sprintf(` +resource "gitlab_user" "foo" { + name = "footest1" + username = "listest%d" + password = "test%dtt" + email = "user%d@test.test" + projects_limit = 3 +} + +resource "gitlab_user" "foo2" { + name = "footest2" + username = "listest%d" + password = "test%dtt" + email = "user%d@test.test" + projects_limit = 2 +} + +data "gitlab_users" "foo" { + search = "user%d@test.test" +} + `, rInt, rInt, rInt, rInt2, rInt2, rInt2, rInt2) +} diff --git a/gitlab/provider.go b/gitlab/provider.go index f3081e54b..cf6bb07df 100644 --- a/gitlab/provider.go +++ b/gitlab/provider.go @@ -44,6 +44,7 @@ func Provider() terraform.ResourceProvider { DataSourcesMap: map[string]*schema.Resource{ "gitlab_project": dataSourceGitlabProject(), "gitlab_user": dataSourceGitlabUser(), + "gitlab_users": dataSourceGitlabUsers(), }, ResourcesMap: map[string]*schema.Resource{ diff --git a/website/docs/d/users.html.markdown b/website/docs/d/users.html.markdown new file mode 100644 index 000000000..507297b4f --- /dev/null +++ b/website/docs/d/users.html.markdown @@ -0,0 +1,81 @@ +--- +layout: "gitlab" +page_title: "GitLab: gitlab_users" +sidebar_current: "docs-gitlab-data-source-users" +description: |- + Looks up gitlab users +--- + +# gitlab\_users + +Provides details about a list of users in the gitlab provider. The results include id, username, email, name and more about the requested users. Users can also be sorted and filtered using several options. + +**NOTE**: Some of the available options require administrator privileges. Please visit [Gitlab API documentation][users_for_admins] for more information. + +## Example Usage + +```hcl +data "gitlab_users" "example" { + sort = "desc" + order_by = "name" + created_before = "2019-01-01" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `search` - (Optional) Search users by username, name or email. + +* `active` - (Optional) Filter users that are active. + +* `blocked` - (Optional) Filter users that are blocked. + +* `order_by` - (Optional) Order the users' list by `id`, `name`, `username`, `created_at` or `updated_at`. (Requires administrator privileges) + +* `sort` - (Optional) Sort users' list in asc or desc order. (Requires administrator privileges) + +* `extern_uid` - (Optional) Lookup users by external UID. (Requires administrator privileges) + +* `extern_provider` - (Optional) Lookup users by external provider. (Requires administrator privileges) + +* `created_before` - (Optional) Search for users created before a specific date. (Requires administrator privileges) + +* `created_after` - (Optional) Search for users created after a specific date. (Requires administrator privileges) + + +## Attributes Reference + +The following attributes are exported: + +* `users` - The list of users. + * `id` - The unique id assigned to the user by the gitlab server. + * `username` - The username of the user. + * `email` - The e-mail address of the user. + * `name` - The name of the user. + * `is_admin` - Whether the user is an admin. + * `can_create_group` - Whether the user can create groups. + * `can_create_project` - Whether the user can create projects. + * `projects_limit` - Number of projects the user can create. + * `created_at` - Date the user was created at. + * `state` - Whether the user is active or blocked. + * `external` - Whether the user is external. + * `extern_uid` - The external UID of the user. + * `provider` - The UID provider of the user. + * `organization` - The organization of the user. + * `two_factor_enabled` - Whether user's two factor auth is enabled. + * `avatar_url` - The avatar URL of the user. + * `bio` - The bio of the user. + * `location` - The location of the user. + * `skype` - Skype username of the user. + * `linkedin` - Linkedin profile of the user. + * `twitter` - Twitter username of the user. + * `website_url` - User's website URL. + * `theme_id` - User's theme ID. + * `color_scheme_id` - User's color scheme ID. + * `last_sign_in_at` - Last user's sign-in date. + * `current_sign_in_at` - Current user's sign-in date. + + +[users_for_admins]: https://docs.gitlab.com/ce/api/users.html#for-admins \ No newline at end of file diff --git a/website/gitlab.erb b/website/gitlab.erb index 21de93721..9162e8784 100644 --- a/website/gitlab.erb +++ b/website/gitlab.erb @@ -19,6 +19,9 @@ > gitlab_user + > + gitlab_users +