2018-11-13 11:17:39 +01:00
|
|
|
package tfe
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"net/url"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Compile-time proof of interface implementation.
|
|
|
|
var _ PolicySets = (*policySets)(nil)
|
|
|
|
|
|
|
|
// PolicySets describes all the policy set related methods that the Terraform
|
|
|
|
// Enterprise API supports.
|
|
|
|
//
|
|
|
|
// TFE API docs: https://www.terraform.io/docs/enterprise/api/policies.html
|
|
|
|
type PolicySets interface {
|
2018-11-15 14:09:38 +01:00
|
|
|
// List all the policy sets for a given organization.
|
2018-11-13 11:17:39 +01:00
|
|
|
List(ctx context.Context, organization string, options PolicySetListOptions) (*PolicySetList, error)
|
|
|
|
|
|
|
|
// Create a policy set and associate it with an organization.
|
|
|
|
Create(ctx context.Context, organization string, options PolicySetCreateOptions) (*PolicySet, error)
|
|
|
|
|
|
|
|
// Read a policy set by its ID.
|
|
|
|
Read(ctx context.Context, policySetID string) (*PolicySet, error)
|
|
|
|
|
|
|
|
// Update an existing policy set.
|
|
|
|
Update(ctx context.Context, policySetID string, options PolicySetUpdateOptions) (*PolicySet, error)
|
|
|
|
|
|
|
|
// Add policies to a policy set.
|
|
|
|
AddPolicies(ctx context.Context, policySetID string, options PolicySetAddPoliciesOptions) error
|
|
|
|
|
|
|
|
// Remove policies from a policy set.
|
|
|
|
RemovePolicies(ctx context.Context, policySetID string, options PolicySetRemovePoliciesOptions) error
|
|
|
|
|
2018-11-15 14:09:38 +01:00
|
|
|
// Add workspaces to a policy set.
|
|
|
|
AddWorkspaces(ctx context.Context, policySetID string, options PolicySetAddWorkspacesOptions) error
|
2018-11-13 11:17:39 +01:00
|
|
|
|
2018-11-15 14:09:38 +01:00
|
|
|
// Remove workspaces from a policy set.
|
|
|
|
RemoveWorkspaces(ctx context.Context, policySetID string, options PolicySetRemoveWorkspacesOptions) error
|
2018-11-13 11:17:39 +01:00
|
|
|
|
|
|
|
// Delete a policy set by its ID.
|
|
|
|
Delete(ctx context.Context, policyID string) error
|
|
|
|
}
|
|
|
|
|
|
|
|
// policySets implements PolicySets.
|
|
|
|
type policySets struct {
|
|
|
|
client *Client
|
|
|
|
}
|
|
|
|
|
2018-11-15 14:09:38 +01:00
|
|
|
// PolicySetList represents a list of policy sets.
|
2018-11-13 11:17:39 +01:00
|
|
|
type PolicySetList struct {
|
|
|
|
*Pagination
|
|
|
|
Items []*PolicySet
|
|
|
|
}
|
|
|
|
|
|
|
|
// PolicySet represents a Terraform Enterprise policy set.
|
|
|
|
type PolicySet struct {
|
|
|
|
ID string `jsonapi:"primary,policy-sets"`
|
|
|
|
Name string `jsonapi:"attr,name"`
|
|
|
|
Description string `jsonapi:"attr,description"`
|
|
|
|
Global bool `jsonapi:"attr,global"`
|
|
|
|
PolicyCount int `jsonapi:"attr,policy-count"`
|
|
|
|
WorkspaceCount int `jsonapi:"attr,workspace-count"`
|
|
|
|
CreatedAt time.Time `jsonapi:"attr,created-at,iso8601"`
|
|
|
|
UpdatedAt time.Time `jsonapi:"attr,updated-at,iso8601"`
|
|
|
|
|
|
|
|
// Relations
|
|
|
|
Organization *Organization `jsonapi:"relation,organization"`
|
|
|
|
Policies []*Policy `jsonapi:"relation,policies"`
|
|
|
|
Workspaces []*Workspace `jsonapi:"relation,workspaces"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// PolicySetListOptions represents the options for listing policy sets.
|
|
|
|
type PolicySetListOptions struct {
|
|
|
|
ListOptions
|
|
|
|
|
|
|
|
// A search string (partial policy set name) used to filter the results.
|
|
|
|
Search *string `url:"search[name],omitempty"`
|
|
|
|
}
|
|
|
|
|
2018-11-15 14:09:38 +01:00
|
|
|
// List all the policies for a given organization.
|
2018-11-13 11:17:39 +01:00
|
|
|
func (s *policySets) List(ctx context.Context, organization string, options PolicySetListOptions) (*PolicySetList, error) {
|
|
|
|
if !validStringID(&organization) {
|
|
|
|
return nil, errors.New("invalid value for organization")
|
|
|
|
}
|
|
|
|
|
|
|
|
u := fmt.Sprintf("organizations/%s/policy-sets", url.QueryEscape(organization))
|
|
|
|
req, err := s.client.newRequest("GET", u, &options)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
psl := &PolicySetList{}
|
|
|
|
err = s.client.do(ctx, req, psl)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return psl, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// PolicySetCreateOptions represents the options for creating a new policy set.
|
|
|
|
type PolicySetCreateOptions struct {
|
|
|
|
// For internal use only!
|
|
|
|
ID string `jsonapi:"primary,policy-sets"`
|
|
|
|
|
|
|
|
// The name of the policy set.
|
|
|
|
Name *string `jsonapi:"attr,name"`
|
|
|
|
|
|
|
|
// The description of the policy set.
|
|
|
|
Description *string `jsonapi:"attr,description,omitempty"`
|
|
|
|
|
|
|
|
// Whether or not the policy set is global.
|
|
|
|
Global *bool `jsonapi:"attr,global,omitempty"`
|
|
|
|
|
|
|
|
// The initial members of the policy set.
|
|
|
|
Policies []*Policy `jsonapi:"relation,policies,omitempty"`
|
|
|
|
|
2018-11-15 14:09:38 +01:00
|
|
|
// The initial list of workspaces for which the policy set should be enforced.
|
2018-11-13 11:17:39 +01:00
|
|
|
Workspaces []*Workspace `jsonapi:"relation,workspaces,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o PolicySetCreateOptions) valid() error {
|
|
|
|
if !validString(o.Name) {
|
|
|
|
return errors.New("name is required")
|
|
|
|
}
|
|
|
|
if !validStringID(o.Name) {
|
|
|
|
return errors.New("invalid value for name")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a policy set and associate it with an organization.
|
|
|
|
func (s *policySets) Create(ctx context.Context, organization string, options PolicySetCreateOptions) (*PolicySet, error) {
|
|
|
|
if !validStringID(&organization) {
|
|
|
|
return nil, errors.New("invalid value for organization")
|
|
|
|
}
|
|
|
|
if err := options.valid(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure we don't send a user provided ID.
|
|
|
|
options.ID = ""
|
|
|
|
|
|
|
|
u := fmt.Sprintf("organizations/%s/policy-sets", url.QueryEscape(organization))
|
|
|
|
req, err := s.client.newRequest("POST", u, &options)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
ps := &PolicySet{}
|
|
|
|
err = s.client.do(ctx, req, ps)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return ps, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read a policy set by its ID.
|
|
|
|
func (s *policySets) Read(ctx context.Context, policySetID string) (*PolicySet, error) {
|
|
|
|
if !validStringID(&policySetID) {
|
|
|
|
return nil, errors.New("invalid value for policy set ID")
|
|
|
|
}
|
|
|
|
|
|
|
|
u := fmt.Sprintf("policy-sets/%s", url.QueryEscape(policySetID))
|
|
|
|
req, err := s.client.newRequest("GET", u, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
ps := &PolicySet{}
|
|
|
|
err = s.client.do(ctx, req, ps)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return ps, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// PolicySetUpdateOptions represents the options for updating a policy set.
|
|
|
|
type PolicySetUpdateOptions struct {
|
|
|
|
// For internal use only!
|
|
|
|
ID string `jsonapi:"primary,policy-sets"`
|
|
|
|
|
|
|
|
/// The name of the policy set.
|
|
|
|
Name *string `jsonapi:"attr,name,omitempty"`
|
|
|
|
|
|
|
|
// The description of the policy set.
|
|
|
|
Description *string `jsonapi:"attr,description,omitempty"`
|
|
|
|
|
|
|
|
// Whether or not the policy set is global.
|
|
|
|
Global *bool `jsonapi:"attr,global,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o PolicySetUpdateOptions) valid() error {
|
|
|
|
if o.Name != nil && !validStringID(o.Name) {
|
|
|
|
return errors.New("invalid value for name")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update an existing policy set.
|
|
|
|
func (s *policySets) Update(ctx context.Context, policySetID string, options PolicySetUpdateOptions) (*PolicySet, error) {
|
|
|
|
if !validStringID(&policySetID) {
|
|
|
|
return nil, errors.New("invalid value for policy set ID")
|
|
|
|
}
|
|
|
|
if err := options.valid(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure we don't send a user provided ID.
|
|
|
|
options.ID = ""
|
|
|
|
|
|
|
|
u := fmt.Sprintf("policy-sets/%s", url.QueryEscape(policySetID))
|
|
|
|
req, err := s.client.newRequest("PATCH", u, &options)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
ps := &PolicySet{}
|
|
|
|
err = s.client.do(ctx, req, ps)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return ps, err
|
|
|
|
}
|
|
|
|
|
2018-11-15 14:09:38 +01:00
|
|
|
// PolicySetAddPoliciesOptions represents the options for adding policies
|
|
|
|
// to a policy set.
|
2018-11-13 11:17:39 +01:00
|
|
|
type PolicySetAddPoliciesOptions struct {
|
|
|
|
/// The policies to add to the policy set.
|
|
|
|
Policies []*Policy
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o PolicySetAddPoliciesOptions) valid() error {
|
|
|
|
if o.Policies == nil {
|
|
|
|
return errors.New("policies is required")
|
|
|
|
}
|
|
|
|
if len(o.Policies) == 0 {
|
|
|
|
return errors.New("must provide at least one policy")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add policies to a policy set
|
|
|
|
func (s *policySets) AddPolicies(ctx context.Context, policySetID string, options PolicySetAddPoliciesOptions) error {
|
|
|
|
if !validStringID(&policySetID) {
|
|
|
|
return errors.New("invalid value for policy set ID")
|
|
|
|
}
|
|
|
|
if err := options.valid(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
u := fmt.Sprintf("policy-sets/%s/relationships/policies", url.QueryEscape(policySetID))
|
|
|
|
req, err := s.client.newRequest("POST", u, options.Policies)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return s.client.do(ctx, req, nil)
|
|
|
|
}
|
|
|
|
|
2018-11-15 14:09:38 +01:00
|
|
|
// PolicySetRemovePoliciesOptions represents the options for removing
|
|
|
|
// policies from a policy set.
|
2018-11-13 11:17:39 +01:00
|
|
|
type PolicySetRemovePoliciesOptions struct {
|
|
|
|
/// The policies to remove from the policy set.
|
|
|
|
Policies []*Policy
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o PolicySetRemovePoliciesOptions) valid() error {
|
|
|
|
if o.Policies == nil {
|
|
|
|
return errors.New("policies is required")
|
|
|
|
}
|
|
|
|
if len(o.Policies) == 0 {
|
|
|
|
return errors.New("must provide at least one policy")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove policies from a policy set
|
|
|
|
func (s *policySets) RemovePolicies(ctx context.Context, policySetID string, options PolicySetRemovePoliciesOptions) error {
|
|
|
|
if !validStringID(&policySetID) {
|
|
|
|
return errors.New("invalid value for policy set ID")
|
|
|
|
}
|
|
|
|
if err := options.valid(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
u := fmt.Sprintf("policy-sets/%s/relationships/policies", url.QueryEscape(policySetID))
|
|
|
|
req, err := s.client.newRequest("DELETE", u, options.Policies)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return s.client.do(ctx, req, nil)
|
|
|
|
}
|
|
|
|
|
2018-11-15 14:09:38 +01:00
|
|
|
// PolicySetAddWorkspacesOptions represents the options for adding workspaces
|
|
|
|
// to a policy set.
|
|
|
|
type PolicySetAddWorkspacesOptions struct {
|
|
|
|
/// The workspaces to add to the policy set.
|
2018-11-13 11:17:39 +01:00
|
|
|
Workspaces []*Workspace
|
|
|
|
}
|
|
|
|
|
2018-11-15 14:09:38 +01:00
|
|
|
func (o PolicySetAddWorkspacesOptions) valid() error {
|
2018-11-13 11:17:39 +01:00
|
|
|
if o.Workspaces == nil {
|
|
|
|
return errors.New("workspaces is required")
|
|
|
|
}
|
|
|
|
if len(o.Workspaces) == 0 {
|
|
|
|
return errors.New("must provide at least one workspace")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-11-15 14:09:38 +01:00
|
|
|
// Add workspaces to a policy set.
|
|
|
|
func (s *policySets) AddWorkspaces(ctx context.Context, policySetID string, options PolicySetAddWorkspacesOptions) error {
|
2018-11-13 11:17:39 +01:00
|
|
|
if !validStringID(&policySetID) {
|
|
|
|
return errors.New("invalid value for policy set ID")
|
|
|
|
}
|
|
|
|
if err := options.valid(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
u := fmt.Sprintf("policy-sets/%s/relationships/workspaces", url.QueryEscape(policySetID))
|
|
|
|
req, err := s.client.newRequest("POST", u, options.Workspaces)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return s.client.do(ctx, req, nil)
|
|
|
|
}
|
|
|
|
|
2018-11-15 14:09:38 +01:00
|
|
|
// PolicySetRemoveWorkspacesOptions represents the options for removing
|
|
|
|
// workspaces from a policy set.
|
|
|
|
type PolicySetRemoveWorkspacesOptions struct {
|
|
|
|
/// The workspaces to remove from the policy set.
|
2018-11-13 11:17:39 +01:00
|
|
|
Workspaces []*Workspace
|
|
|
|
}
|
|
|
|
|
2018-11-15 14:09:38 +01:00
|
|
|
func (o PolicySetRemoveWorkspacesOptions) valid() error {
|
2018-11-13 11:17:39 +01:00
|
|
|
if o.Workspaces == nil {
|
|
|
|
return errors.New("workspaces is required")
|
|
|
|
}
|
|
|
|
if len(o.Workspaces) == 0 {
|
|
|
|
return errors.New("must provide at least one workspace")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-11-15 14:09:38 +01:00
|
|
|
// Remove workspaces from a policy set.
|
|
|
|
func (s *policySets) RemoveWorkspaces(ctx context.Context, policySetID string, options PolicySetRemoveWorkspacesOptions) error {
|
2018-11-13 11:17:39 +01:00
|
|
|
if !validStringID(&policySetID) {
|
|
|
|
return errors.New("invalid value for policy set ID")
|
|
|
|
}
|
|
|
|
if err := options.valid(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
u := fmt.Sprintf("policy-sets/%s/relationships/workspaces", url.QueryEscape(policySetID))
|
|
|
|
req, err := s.client.newRequest("DELETE", u, options.Workspaces)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return s.client.do(ctx, req, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete a policy set by its ID.
|
|
|
|
func (s *policySets) Delete(ctx context.Context, policySetID string) error {
|
|
|
|
if !validStringID(&policySetID) {
|
|
|
|
return errors.New("invalid value for policy set ID")
|
|
|
|
}
|
|
|
|
|
|
|
|
u := fmt.Sprintf("policy-sets/%s", url.QueryEscape(policySetID))
|
|
|
|
req, err := s.client.newRequest("DELETE", u, nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return s.client.do(ctx, req, nil)
|
|
|
|
}
|