From e4f332c362a295fe6971dc1c346a0bbd0fb3efd7 Mon Sep 17 00:00:00 2001 From: Gavin Bunney Date: Fri, 11 Oct 2019 08:02:21 -0700 Subject: [PATCH] Added `data.bitbucketserver_global_permissions_groups` and `data.bitbucketserver_global_permissions_users` --- README.md | 34 +++- bitbucket/data_global_permissions_groups.go | 128 +++++++++++++++ .../data_global_permissions_groups_test.go | 72 +++++++++ bitbucket/data_global_permissions_users.go | 152 ++++++++++++++++++ .../data_global_permissions_users_test.go | 78 +++++++++ bitbucket/provider.go | 2 + 6 files changed, 464 insertions(+), 2 deletions(-) create mode 100644 bitbucket/data_global_permissions_groups.go create mode 100644 bitbucket/data_global_permissions_groups_test.go create mode 100644 bitbucket/data_global_permissions_users.go create mode 100644 bitbucket/data_global_permissions_users_test.go diff --git a/README.md b/README.md index 4439146..7a60269 100644 --- a/README.md +++ b/README.md @@ -320,7 +320,37 @@ data "bitbucketserver_group_users" "stash-users" { * `users` - List of users containing `name`, `email_address`, `display_name` and `active` keys. -### Project Permissions Groups +### Global Permissions - Groups + +Retrieve a list of groups that have been granted at least one global permission. + +```hcl +data "bitbucketserver_global_permissions_groups" "all" { } +``` + +* `filter` - Optional. If specified only group names containing the supplied string will be returned. + +#### Attributes + +* `groups` - List of maps containing `name` and `permission` keys. Available permissions are: `LICENSED_USER`, `PROJECT_CREATE`, `ADMIN`, `SYS_ADMIN` + + +### Global Permissions - Users + +Retrieve a list of users that have been granted at least one global permission. + +```hcl +data "bitbucketserver_global_permissions_users" "proj" { } +``` + +* `filter` - Optional. If specified only user names containing the supplied string will be returned. + +#### Attributes + +* `users` - List of maps containing `name`, `email_address`, `display_name`, `active` and `permission` keys. Available permissions are: `LICENSED_USER`, `PROJECT_CREATE`, `ADMIN`, `SYS_ADMIN` + + +### Project Permissions - Groups Retrieve a list of groups that have been granted at least one permission for the specified project. @@ -338,7 +368,7 @@ data "bitbucketserver_project_permissions_groups" "proj" { * `groups` - List of maps containing `name` and `permission` keys. -### Project Permissions Users +### Project Permissions - Users Retrieve a list of users that have been granted at least one permission for the specified project. diff --git a/bitbucket/data_global_permissions_groups.go b/bitbucket/data_global_permissions_groups.go new file mode 100644 index 0000000..3269d84 --- /dev/null +++ b/bitbucket/data_global_permissions_groups.go @@ -0,0 +1,128 @@ +package bitbucket + +import ( + "encoding/json" + "fmt" + "github.com/hashicorp/terraform/helper/schema" + "net/url" +) + +type PaginatedGlobalPermissionsGroupsValue struct { + Group struct { + Name string `json:"name,omitempty"` + } `json:"group,omitempty"` + Permission string `json:"permission,omitempty"` +} + +type GlobalPermissionsGroup struct { + Name string + Permission string +} + +type PaginatedGlobalPermissionsGroups struct { + Values []PaginatedGlobalPermissionsGroupsValue `json:"values,omitempty"` + Size int `json:"size,omitempty"` + Limit int `json:"limit,omitempty"` + IsLastPage bool `json:"isLastPage,omitempty"` + Start int `json:"start,omitempty"` + NextPageStart int `json:"nextPageStart,omitempty"` +} + +func dataSourceGlobalPermissionsGroups() *schema.Resource { + return &schema.Resource{ + Read: dataSourceGlobalPermissionsGroupsRead, + + Schema: map[string]*schema.Schema{ + "filter": { + Type: schema.TypeString, + Optional: true, + }, + "groups": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "permission": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceGlobalPermissionsGroupsRead(d *schema.ResourceData, m interface{}) error { + groups, err := readGlobalPermissionsGroups(m, d.Get("filter").(string)) + if err != nil { + return err + } + + d.SetId("global-permissions-groups") + + var terraformGroups []interface{} + for _, group := range groups { + g := make(map[string]interface{}) + g["name"] = group.Name + g["permission"] = group.Permission + terraformGroups = append(terraformGroups, g) + } + + _ = d.Set("groups", terraformGroups) + return nil +} + +func readGlobalPermissionsGroups(m interface{}, filter string) ([]GlobalPermissionsGroup, error) { + client := m.(*BitbucketClient) + + resourceURL := "/rest/api/1.0/admin/permissions/groups" + + if filter != "" { + resourceURL += "?filter=" + url.QueryEscape(filter) + } + + var groupGroups PaginatedGlobalPermissionsGroups + var groups []GlobalPermissionsGroup + + for { + resp, err := client.Get(resourceURL) + if err != nil { + return nil, err + } + + decoder := json.NewDecoder(resp.Body) + err = decoder.Decode(&groupGroups) + if err != nil { + return nil, err + } + + for _, group := range groupGroups.Values { + g := GlobalPermissionsGroup{ + Name: group.Group.Name, + Permission: group.Permission, + } + groups = append(groups, g) + } + + if groupGroups.IsLastPage == false { + resourceURL = fmt.Sprintf("/rest/api/1.0/admin/permissions/groups?start=%d", + groupGroups.NextPageStart, + ) + + if filter != "" { + resourceURL += "&filter=" + url.QueryEscape(filter) + } + + groupGroups = PaginatedGlobalPermissionsGroups{} + } else { + break + } + } + + return groups, nil +} diff --git a/bitbucket/data_global_permissions_groups_test.go b/bitbucket/data_global_permissions_groups_test.go new file mode 100644 index 0000000..93509ad --- /dev/null +++ b/bitbucket/data_global_permissions_groups_test.go @@ -0,0 +1,72 @@ +package bitbucket + +import ( + "github.com/hashicorp/terraform/helper/resource" + "testing" +) + +func TestAccBitbucketDataGlobalPermissionsGroups_basic(t *testing.T) { + config := ` + data "bitbucketserver_global_permissions_groups" "test" { + } + ` + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.bitbucketserver_global_permissions_groups.test", "groups.#", "1"), + resource.TestCheckResourceAttr("data.bitbucketserver_global_permissions_groups.test", "groups.0.name", "stash-users"), + resource.TestCheckResourceAttr("data.bitbucketserver_global_permissions_groups.test", "groups.0.permission", "LICENSED_USER"), + ), + }, + }, + }) +} + +func TestAccBitbucketDataGlobalPermissionsGroups_filter(t *testing.T) { + config := ` + data "bitbucketserver_global_permissions_groups" "test" { + filter = "stash-users" + } + ` + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.bitbucketserver_global_permissions_groups.test", "groups.#", "1"), + resource.TestCheckResourceAttr("data.bitbucketserver_global_permissions_groups.test", "groups.0.name", "stash-users"), + resource.TestCheckResourceAttr("data.bitbucketserver_global_permissions_groups.test", "groups.0.permission", "LICENSED_USER"), + ), + }, + }, + }) +} + +func TestAccBitbucketDataGlobalPermissionsGroups_filter_no_match(t *testing.T) { + config := ` + data "bitbucketserver_global_permissions_groups" "test" { + filter = "stashing" + } + ` + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.bitbucketserver_global_permissions_groups.test", "groups.#", "0"), + ), + }, + }, + }) +} diff --git a/bitbucket/data_global_permissions_users.go b/bitbucket/data_global_permissions_users.go new file mode 100644 index 0000000..95ad08a --- /dev/null +++ b/bitbucket/data_global_permissions_users.go @@ -0,0 +1,152 @@ +package bitbucket + +import ( + "encoding/json" + "fmt" + "github.com/hashicorp/terraform/helper/schema" + "net/url" +) + +type PaginatedGlobalPermissionsUsersValue struct { + User struct { + Name string `json:"name,omitempty"` + EmailAddress string `json:"emailAddress,omitempty"` + DisplayName string `json:"displayName,omitempty"` + Active bool `json:"active,omitempty"` + } `json:"user,omitempty"` + Permission string `json:"permission,omitempty"` +} + +type GlobalPermissionsUser struct { + Name string + EmailAddress string + DisplayName string + Active bool + Permission string +} + +type PaginatedGlobalPermissionsUsers struct { + Values []PaginatedGlobalPermissionsUsersValue `json:"values,omitempty"` + Size int `json:"size,omitempty"` + Limit int `json:"limit,omitempty"` + IsLastPage bool `json:"isLastPage,omitempty"` + Start int `json:"start,omitempty"` + NextPageStart int `json:"nextPageStart,omitempty"` +} + +func dataSourceGlobalPermissionsUsers() *schema.Resource { + return &schema.Resource{ + Read: dataSourceGlobalPermissionsUsersRead, + + Schema: map[string]*schema.Schema{ + "filter": { + Type: schema.TypeString, + Optional: true, + }, + "users": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "email_address": { + Type: schema.TypeString, + Computed: true, + }, + "display_name": { + Type: schema.TypeString, + Computed: true, + }, + "active": { + Type: schema.TypeBool, + Computed: true, + }, + "permission": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceGlobalPermissionsUsersRead(d *schema.ResourceData, m interface{}) error { + users, err := readGlobalPermissionsUsers(m, d.Get("filter").(string)) + if err != nil { + return err + } + + d.SetId("global-permissions-users") + + var terraformUsers []interface{} + for _, group := range users { + g := make(map[string]interface{}) + g["name"] = group.Name + g["email_address"] = group.EmailAddress + g["display_name"] = group.DisplayName + g["active"] = group.Active + g["permission"] = group.Permission + terraformUsers = append(terraformUsers, g) + } + + _ = d.Set("users", terraformUsers) + return nil +} + +func readGlobalPermissionsUsers(m interface{}, filter string) ([]GlobalPermissionsUser, error) { + client := m.(*BitbucketClient) + + resourceURL := "/rest/api/1.0/admin/permissions/users" + + if filter != "" { + resourceURL += "?filter=" + url.QueryEscape(filter) + } + + var globalUsers PaginatedGlobalPermissionsUsers + var users []GlobalPermissionsUser + + for { + resp, err := client.Get(resourceURL) + if err != nil { + return nil, err + } + + decoder := json.NewDecoder(resp.Body) + err = decoder.Decode(&globalUsers) + if err != nil { + return nil, err + } + + for _, user := range globalUsers.Values { + g := GlobalPermissionsUser{ + Name: user.User.Name, + EmailAddress: user.User.EmailAddress, + DisplayName: user.User.DisplayName, + Active: user.User.Active, + Permission: user.Permission, + } + users = append(users, g) + } + + if globalUsers.IsLastPage == false { + resourceURL = fmt.Sprintf("/rest/api/1.0/admin/permissions/users?start=%d", + globalUsers.NextPageStart, + ) + + if filter != "" { + resourceURL += "&filter=" + url.QueryEscape(filter) + } + + globalUsers = PaginatedGlobalPermissionsUsers{} + } else { + break + } + } + + return users, nil +} diff --git a/bitbucket/data_global_permissions_users_test.go b/bitbucket/data_global_permissions_users_test.go new file mode 100644 index 0000000..34a3f51 --- /dev/null +++ b/bitbucket/data_global_permissions_users_test.go @@ -0,0 +1,78 @@ +package bitbucket + +import ( + "github.com/hashicorp/terraform/helper/resource" + "testing" +) + +func TestAccBitbucketDataGlobalPermissionsUsers_basic(t *testing.T) { + config := ` + data "bitbucketserver_global_permissions_users" "test" { + } + ` + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.bitbucketserver_global_permissions_users.test", "users.#", "1"), + resource.TestCheckResourceAttr("data.bitbucketserver_global_permissions_users.test", "users.0.name", "admin"), + resource.TestCheckResourceAttr("data.bitbucketserver_global_permissions_users.test", "users.0.display_name", "Admin"), + resource.TestCheckResourceAttr("data.bitbucketserver_global_permissions_users.test", "users.0.email_address", "admin@example.com"), + resource.TestCheckResourceAttr("data.bitbucketserver_global_permissions_users.test", "users.0.active", "true"), + resource.TestCheckResourceAttr("data.bitbucketserver_global_permissions_users.test", "users.0.permission", "SYS_ADMIN"), + ), + }, + }, + }) +} + +func TestAccBitbucketDataGlobalPermissionsUsers_filter(t *testing.T) { + config := ` + data "bitbucketserver_global_permissions_users" "test" { + filter = "admin" + } + ` + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.bitbucketserver_global_permissions_users.test", "users.#", "1"), + resource.TestCheckResourceAttr("data.bitbucketserver_global_permissions_users.test", "users.0.name", "admin"), + resource.TestCheckResourceAttr("data.bitbucketserver_global_permissions_users.test", "users.0.display_name", "Admin"), + resource.TestCheckResourceAttr("data.bitbucketserver_global_permissions_users.test", "users.0.email_address", "admin@example.com"), + resource.TestCheckResourceAttr("data.bitbucketserver_global_permissions_users.test", "users.0.active", "true"), + resource.TestCheckResourceAttr("data.bitbucketserver_global_permissions_users.test", "users.0.permission", "SYS_ADMIN"), + ), + }, + }, + }) +} + +func TestAccBitbucketDataGlobalPermissionsUsers_filter_no_match(t *testing.T) { + config := ` + data "bitbucketserver_global_permissions_users" "test" { + filter = "admining-the-country-side" + } + ` + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.bitbucketserver_global_permissions_users.test", "users.#", "0"), + ), + }, + }, + }) +} diff --git a/bitbucket/provider.go b/bitbucket/provider.go index 0b51878..028ae21 100644 --- a/bitbucket/provider.go +++ b/bitbucket/provider.go @@ -30,6 +30,8 @@ func Provider() terraform.ResourceProvider { ConfigureFunc: providerConfigure, DataSourcesMap: map[string]*schema.Resource{ "bitbucketserver_application_properties": dataSourceApplicationProperties(), + "bitbucketserver_global_permissions_groups": dataSourceGlobalPermissionsGroups(), + "bitbucketserver_global_permissions_users": dataSourceGlobalPermissionsUsers(), "bitbucketserver_groups": dataSourceGroups(), "bitbucketserver_group_users": dataSourceGroupUsers(), "bitbucketserver_project_permissions_groups": dataSourceProjectPermissionsGroups(),