Skip to content

Commit

Permalink
Merge pull request #288 from hashicorp/brandonc/module-consumers
Browse files Browse the repository at this point in the history
Add admin/organization/relationships/module-consumers endpoint
  • Loading branch information
brandonc committed Jan 5, 2022
2 parents 0c9b270 + 639bf78 commit 73c3b41
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 0 deletions.
64 changes: 64 additions & 0 deletions admin_organization.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ type AdminOrganizations interface {

// Delete an organization by its name via admin API
Delete(ctx context.Context, organization string) error

// ListModuleConsumers lists specific organizations in the Terraform Enterprise installation that have permission to use an organization's modules.
ListModuleConsumers(ctx context.Context, organization string, options AdminOrganizationListModuleConsumersOptions) (*AdminOrganizationList, error)

// UpdateModuleConsumers specifies a list of organizations that can use modules from the sharing organization's private registry. Setting a list of module consumers will turn off global module sharing for an organization.
UpdateModuleConsumers(ctx context.Context, organization string, consumerOrganizations []string) error
}

// adminOrganizations implements AdminOrganizations.
Expand Down Expand Up @@ -77,6 +83,15 @@ type AdminOrganizationListOptions struct {
Include *string `url:"include"`
}

// AdminOrganizationListModuleConsumersOptions represents the options for listing organization module consumers through the Admin API
type AdminOrganizationListModuleConsumersOptions struct {
ListOptions
}

type AdminOrganizationID struct {
ID string `jsonapi:"primary,organizations"`
}

// List all the organizations visible to the current user.
func (s *adminOrganizations) List(ctx context.Context, options AdminOrganizationListOptions) (*AdminOrganizationList, error) {
url := "admin/organizations"
Expand All @@ -94,6 +109,27 @@ func (s *adminOrganizations) List(ctx context.Context, options AdminOrganization
return orgl, nil
}

func (s *adminOrganizations) ListModuleConsumers(ctx context.Context, organization string, options AdminOrganizationListModuleConsumersOptions) (*AdminOrganizationList, error) {
if !validStringID(&organization) {
return nil, ErrInvalidOrg
}

url := fmt.Sprintf("admin/organizations/%s/relationships/module-consumers", url.QueryEscape(organization))

req, err := s.client.newRequest("GET", url, nil)
if err != nil {
return nil, err
}

orgl := &AdminOrganizationList{}
err = s.client.do(ctx, req, orgl)
if err != nil {
return nil, err
}

return orgl, nil
}

func (s *adminOrganizations) Read(ctx context.Context, organization string) (*AdminOrganization, error) {
if !validStringID(&organization) {
return nil, ErrInvalidOrg
Expand Down Expand Up @@ -134,6 +170,34 @@ func (s *adminOrganizations) Update(ctx context.Context, organization string, op
return org, nil
}

func (s *adminOrganizations) UpdateModuleConsumers(ctx context.Context, organization string, consumerOrganizationIDs []string) error {
if !validStringID(&organization) {
return ErrInvalidOrg
}

url := fmt.Sprintf("admin/organizations/%s/relationships/module-consumers", url.QueryEscape(organization))

var organizations []*AdminOrganizationID
for _, id := range consumerOrganizationIDs {
if !validStringID(&id) {
return ErrInvalidOrg
}
organizations = append(organizations, &AdminOrganizationID{ID: id})
}

req, err := s.client.newRequest("PATCH", url, organizations)
if err != nil {
return err
}

err = s.client.do(ctx, req, nil)
if err != nil {
return err
}

return nil
}

// Delete an organization by its name.
func (s *adminOrganizations) Delete(ctx context.Context, organization string) error {
if !validStringID(&organization) {
Expand Down
44 changes: 44 additions & 0 deletions admin_organization_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,50 @@ func TestAdminOrganizations_Delete(t *testing.T) {
})
}

func TestAdminOrganizations_ModuleConsumers(t *testing.T) {
skipIfCloud(t)

client := testClient(t)
ctx := context.Background()

t.Run("returns error if invalid org string is used", func(t *testing.T) {
org1, org1TestCleanup := createOrganization(t, client)
defer org1TestCleanup()

err := client.Admin.Organizations.UpdateModuleConsumers(ctx, org1.Name, []string{"1Hello!"})
assert.EqualError(t, err, ErrInvalidOrg.Error())
})

t.Run("can list and update module consumers", func(t *testing.T) {
org1, org1TestCleanup := createOrganization(t, client)
defer org1TestCleanup()

org2, org2TestCleanup := createOrganization(t, client)
defer org2TestCleanup()

err := client.Admin.Organizations.UpdateModuleConsumers(ctx, org1.Name, []string{org2.Name})
assert.NoError(t, err)

adminModuleConsumerList, err := client.Admin.Organizations.ListModuleConsumers(ctx, org1.Name, AdminOrganizationListModuleConsumersOptions{})
require.NoError(t, err)

assert.Equal(t, len(adminModuleConsumerList.Items), 1)
assert.Equal(t, adminModuleConsumerList.Items[0].Name, org2.Name)

org3, org3TestCleanup := createOrganization(t, client)
defer org3TestCleanup()

err = client.Admin.Organizations.UpdateModuleConsumers(ctx, org1.Name, []string{org3.Name})
assert.NoError(t, err)

adminModuleConsumerList, err = client.Admin.Organizations.ListModuleConsumers(ctx, org1.Name, AdminOrganizationListModuleConsumersOptions{})
require.NoError(t, err)

assert.Equal(t, len(adminModuleConsumerList.Items), 1)
assert.Equal(t, adminModuleConsumerList.Items[0].Name, org3.Name)
})
}

func TestAdminOrganizations_Update(t *testing.T) {
skipIfCloud(t)

Expand Down
29 changes: 29 additions & 0 deletions mocks/admin_organization_mocks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 73c3b41

Please sign in to comment.