368 lines
11 KiB
Go
368 lines
11 KiB
Go
package tfe
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
"time"
|
|
)
|
|
|
|
// Compile-time proof of interface implementation.
|
|
var _ Organizations = (*organizations)(nil)
|
|
|
|
// Organizations describes all the organization related methods that the
|
|
// Terraform Enterprise API supports.
|
|
//
|
|
// TFE API docs:
|
|
// https://www.terraform.io/docs/enterprise/api/organizations.html
|
|
type Organizations interface {
|
|
// List all the organizations visible to the current user.
|
|
List(ctx context.Context, options OrganizationListOptions) (*OrganizationList, error)
|
|
|
|
// Create a new organization with the given options.
|
|
Create(ctx context.Context, options OrganizationCreateOptions) (*Organization, error)
|
|
|
|
// Read an organization by its name.
|
|
Read(ctx context.Context, organization string) (*Organization, error)
|
|
|
|
// Update attributes of an existing organization.
|
|
Update(ctx context.Context, organization string, options OrganizationUpdateOptions) (*Organization, error)
|
|
|
|
// Delete an organization by its name.
|
|
Delete(ctx context.Context, organization string) error
|
|
|
|
// Capacity shows the current run capacity of an organization.
|
|
Capacity(ctx context.Context, organization string) (*Capacity, error)
|
|
|
|
// Entitlements shows the entitlements of an organization.
|
|
Entitlements(ctx context.Context, organization string) (*Entitlements, error)
|
|
|
|
// RunQueue shows the current run queue of an organization.
|
|
RunQueue(ctx context.Context, organization string, options RunQueueOptions) (*RunQueue, error)
|
|
}
|
|
|
|
// organizations implements Organizations.
|
|
type organizations struct {
|
|
client *Client
|
|
}
|
|
|
|
// AuthPolicyType represents an authentication policy type.
|
|
type AuthPolicyType string
|
|
|
|
// List of available authentication policies.
|
|
const (
|
|
AuthPolicyPassword AuthPolicyType = "password"
|
|
AuthPolicyTwoFactor AuthPolicyType = "two_factor_mandatory"
|
|
)
|
|
|
|
// EnterprisePlanType represents an enterprise plan type.
|
|
type EnterprisePlanType string
|
|
|
|
// List of available enterprise plan types.
|
|
const (
|
|
EnterprisePlanDisabled EnterprisePlanType = "disabled"
|
|
EnterprisePlanPremium EnterprisePlanType = "premium"
|
|
EnterprisePlanPro EnterprisePlanType = "pro"
|
|
EnterprisePlanTrial EnterprisePlanType = "trial"
|
|
)
|
|
|
|
// OrganizationList represents a list of organizations.
|
|
type OrganizationList struct {
|
|
*Pagination
|
|
Items []*Organization
|
|
}
|
|
|
|
// Organization represents a Terraform Enterprise organization.
|
|
type Organization struct {
|
|
Name string `jsonapi:"primary,organizations"`
|
|
CollaboratorAuthPolicy AuthPolicyType `jsonapi:"attr,collaborator-auth-policy"`
|
|
CostEstimationEnabled bool `jsonapi:"attr,cost-estimation-enabled"`
|
|
CreatedAt time.Time `jsonapi:"attr,created-at,iso8601"`
|
|
Email string `jsonapi:"attr,email"`
|
|
EnterprisePlan EnterprisePlanType `jsonapi:"attr,enterprise-plan"`
|
|
OwnersTeamSAMLRoleID string `jsonapi:"attr,owners-team-saml-role-id"`
|
|
Permissions *OrganizationPermissions `jsonapi:"attr,permissions"`
|
|
SAMLEnabled bool `jsonapi:"attr,saml-enabled"`
|
|
SessionRemember int `jsonapi:"attr,session-remember"`
|
|
SessionTimeout int `jsonapi:"attr,session-timeout"`
|
|
TrialExpiresAt time.Time `jsonapi:"attr,trial-expires-at,iso8601"`
|
|
TwoFactorConformant bool `jsonapi:"attr,two-factor-conformant"`
|
|
}
|
|
|
|
// Capacity represents the current run capacity of an organization.
|
|
type Capacity struct {
|
|
Organization string `jsonapi:"primary,organization-capacity"`
|
|
Pending int `jsonapi:"attr,pending"`
|
|
Running int `jsonapi:"attr,running"`
|
|
}
|
|
|
|
// Entitlements represents the entitlements of an organization.
|
|
type Entitlements struct {
|
|
ID string `jsonapi:"primary,entitlement-sets"`
|
|
Operations bool `jsonapi:"attr,operations"`
|
|
PrivateModuleRegistry bool `jsonapi:"attr,private-module-registry"`
|
|
Sentinel bool `jsonapi:"attr,sentinel"`
|
|
StateStorage bool `jsonapi:"attr,state-storage"`
|
|
Teams bool `jsonapi:"attr,teams"`
|
|
VCSIntegrations bool `jsonapi:"attr,vcs-integrations"`
|
|
}
|
|
|
|
// RunQueue represents the current run queue of an organization.
|
|
type RunQueue struct {
|
|
*Pagination
|
|
Items []*Run
|
|
}
|
|
|
|
// OrganizationPermissions represents the organization permissions.
|
|
type OrganizationPermissions struct {
|
|
CanCreateTeam bool `json:"can-create-team"`
|
|
CanCreateWorkspace bool `json:"can-create-workspace"`
|
|
CanCreateWorkspaceMigration bool `json:"can-create-workspace-migration"`
|
|
CanDestroy bool `json:"can-destroy"`
|
|
CanTraverse bool `json:"can-traverse"`
|
|
CanUpdate bool `json:"can-update"`
|
|
CanUpdateAPIToken bool `json:"can-update-api-token"`
|
|
CanUpdateOAuth bool `json:"can-update-oauth"`
|
|
CanUpdateSentinel bool `json:"can-update-sentinel"`
|
|
}
|
|
|
|
// OrganizationListOptions represents the options for listing organizations.
|
|
type OrganizationListOptions struct {
|
|
ListOptions
|
|
}
|
|
|
|
// List all the organizations visible to the current user.
|
|
func (s *organizations) List(ctx context.Context, options OrganizationListOptions) (*OrganizationList, error) {
|
|
req, err := s.client.newRequest("GET", "organizations", &options)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
orgl := &OrganizationList{}
|
|
err = s.client.do(ctx, req, orgl)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return orgl, nil
|
|
}
|
|
|
|
// OrganizationCreateOptions represents the options for creating an organization.
|
|
type OrganizationCreateOptions struct {
|
|
// For internal use only!
|
|
ID string `jsonapi:"primary,organizations"`
|
|
|
|
// Name of the organization.
|
|
Name *string `jsonapi:"attr,name"`
|
|
|
|
// Admin email address.
|
|
Email *string `jsonapi:"attr,email"`
|
|
|
|
// Session expiration (minutes).
|
|
SessionRemember *int `jsonapi:"attr,session-remember,omitempty"`
|
|
|
|
// Session timeout after inactivity (minutes).
|
|
SessionTimeout *int `jsonapi:"attr,session-timeout,omitempty"`
|
|
|
|
// Authentication policy.
|
|
CollaboratorAuthPolicy *AuthPolicyType `jsonapi:"attr,collaborator-auth-policy,omitempty"`
|
|
|
|
// Enable Cost Estimation
|
|
CostEstimationEnabled *bool `jsonapi:"attr,cost-estimation-enabled,omitempty"`
|
|
|
|
// The name of the "owners" team
|
|
OwnersTeamSAMLRoleID *string `jsonapi:"attr,owners-team-saml-role-id,omitempty"`
|
|
}
|
|
|
|
func (o OrganizationCreateOptions) valid() error {
|
|
if !validString(o.Name) {
|
|
return errors.New("name is required")
|
|
}
|
|
if !validStringID(o.Name) {
|
|
return errors.New("invalid value for name")
|
|
}
|
|
if !validString(o.Email) {
|
|
return errors.New("email is required")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Create a new organization with the given options.
|
|
func (s *organizations) Create(ctx context.Context, options OrganizationCreateOptions) (*Organization, error) {
|
|
if err := options.valid(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Make sure we don't send a user provided ID.
|
|
options.ID = ""
|
|
|
|
req, err := s.client.newRequest("POST", "organizations", &options)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
org := &Organization{}
|
|
err = s.client.do(ctx, req, org)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return org, nil
|
|
}
|
|
|
|
// Read an organization by its name.
|
|
func (s *organizations) Read(ctx context.Context, organization string) (*Organization, error) {
|
|
if !validStringID(&organization) {
|
|
return nil, errors.New("invalid value for organization")
|
|
}
|
|
|
|
u := fmt.Sprintf("organizations/%s", url.QueryEscape(organization))
|
|
req, err := s.client.newRequest("GET", u, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
org := &Organization{}
|
|
err = s.client.do(ctx, req, org)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return org, nil
|
|
}
|
|
|
|
// OrganizationUpdateOptions represents the options for updating an organization.
|
|
type OrganizationUpdateOptions struct {
|
|
// For internal use only!
|
|
ID string `jsonapi:"primary,organizations"`
|
|
|
|
// New name for the organization.
|
|
Name *string `jsonapi:"attr,name,omitempty"`
|
|
|
|
// New admin email address.
|
|
Email *string `jsonapi:"attr,email,omitempty"`
|
|
|
|
// Session expiration (minutes).
|
|
SessionRemember *int `jsonapi:"attr,session-remember,omitempty"`
|
|
|
|
// Session timeout after inactivity (minutes).
|
|
SessionTimeout *int `jsonapi:"attr,session-timeout,omitempty"`
|
|
|
|
// Authentication policy.
|
|
CollaboratorAuthPolicy *AuthPolicyType `jsonapi:"attr,collaborator-auth-policy,omitempty"`
|
|
|
|
// Enable Cost Estimation
|
|
CostEstimationEnabled *bool `jsonapi:"attr,cost-estimation-enabled,omitempty"`
|
|
|
|
// The name of the "owners" team
|
|
OwnersTeamSAMLRoleID *string `jsonapi:"attr,owners-team-saml-role-id,omitempty"`
|
|
}
|
|
|
|
// Update attributes of an existing organization.
|
|
func (s *organizations) Update(ctx context.Context, organization string, options OrganizationUpdateOptions) (*Organization, error) {
|
|
if !validStringID(&organization) {
|
|
return nil, errors.New("invalid value for organization")
|
|
}
|
|
|
|
// Make sure we don't send a user provided ID.
|
|
options.ID = ""
|
|
|
|
u := fmt.Sprintf("organizations/%s", url.QueryEscape(organization))
|
|
req, err := s.client.newRequest("PATCH", u, &options)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
org := &Organization{}
|
|
err = s.client.do(ctx, req, org)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return org, nil
|
|
}
|
|
|
|
// Delete an organization by its name.
|
|
func (s *organizations) Delete(ctx context.Context, organization string) error {
|
|
if !validStringID(&organization) {
|
|
return errors.New("invalid value for organization")
|
|
}
|
|
|
|
u := fmt.Sprintf("organizations/%s", url.QueryEscape(organization))
|
|
req, err := s.client.newRequest("DELETE", u, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return s.client.do(ctx, req, nil)
|
|
}
|
|
|
|
// Capacity shows the currently used capacity of an organization.
|
|
func (s *organizations) Capacity(ctx context.Context, organization string) (*Capacity, error) {
|
|
if !validStringID(&organization) {
|
|
return nil, errors.New("invalid value for organization")
|
|
}
|
|
|
|
u := fmt.Sprintf("organizations/%s/capacity", url.QueryEscape(organization))
|
|
req, err := s.client.newRequest("GET", u, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
c := &Capacity{}
|
|
err = s.client.do(ctx, req, c)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return c, nil
|
|
}
|
|
|
|
// Entitlements shows the entitlements of an organization.
|
|
func (s *organizations) Entitlements(ctx context.Context, organization string) (*Entitlements, error) {
|
|
if !validStringID(&organization) {
|
|
return nil, errors.New("invalid value for organization")
|
|
}
|
|
|
|
u := fmt.Sprintf("organizations/%s/entitlement-set", url.QueryEscape(organization))
|
|
req, err := s.client.newRequest("GET", u, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
e := &Entitlements{}
|
|
err = s.client.do(ctx, req, e)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return e, nil
|
|
}
|
|
|
|
// RunQueueOptions represents the options for showing the queue.
|
|
type RunQueueOptions struct {
|
|
ListOptions
|
|
}
|
|
|
|
// RunQueue shows the current run queue of an organization.
|
|
func (s *organizations) RunQueue(ctx context.Context, organization string, options RunQueueOptions) (*RunQueue, error) {
|
|
if !validStringID(&organization) {
|
|
return nil, errors.New("invalid value for organization")
|
|
}
|
|
|
|
u := fmt.Sprintf("organizations/%s/runs/queue", url.QueryEscape(organization))
|
|
req, err := s.client.newRequest("GET", u, &options)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
rq := &RunQueue{}
|
|
err = s.client.do(ctx, req, rq)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return rq, nil
|
|
}
|