Skip to content

Commit

Permalink
Merged automatically by CI pipeline
Browse files Browse the repository at this point in the history
SCALRCORE-21781 Scalr Provider > Service Accounts Creation
  • Loading branch information
emocharnik committed Jan 16, 2023
2 parents 99389a2 + a859777 commit 6329293
Show file tree
Hide file tree
Showing 5 changed files with 470 additions and 18 deletions.
25 changes: 25 additions & 0 deletions helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,31 @@ func createProviderConfigurationScalr(t *testing.T, client *Client, providerName
}
}

func createServiceAccount(
t *testing.T,
client *Client,
account *Account,
status *ServiceAccountStatus) (*ServiceAccount, func()) {
ctx := context.Background()
sa, err := client.ServiceAccounts.Create(ctx, ServiceAccountCreateOptions{
Name: String("tst-" + randomString(t)),
Description: String("tst-description-" + randomString(t)),
Status: status,
Account: account,
})
if err != nil {
t.Fatal(err)
}

return sa, func() {
if err := client.ServiceAccounts.Delete(ctx, sa.ID); err != nil {
t.Errorf("Error destroying service account! WARNING: Dangling resources\n"+
"may exist! The full error is shown below.\n\n"+
"Service account: %s\nError: %s", sa.ID, err)
}
}
}

func assignTagsToWorkspace(t *testing.T, client *Client, workspace *Workspace, tags []*Tag) {
ctx := context.Background()
tagRels := make([]*TagRelation, len(tags))
Expand Down
28 changes: 15 additions & 13 deletions scalr.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,35 +116,36 @@ type Client struct {
retryLogHook RetryLogHook
retryServerErrors bool

Accounts Accounts
AccessPolicies AccessPolicies
AccessTokens AccessTokens
AccountUsers AccountUsers
Accounts Accounts
AgentPoolTokens AgentPoolTokens
AgentPools AgentPools
ConfigurationVersions ConfigurationVersions
Endpoints Endpoints
Environments Environments
EnvironmentTags EnvironmentTags
Environments Environments
ModuleVersions ModuleVersions
Modules Modules
PolicyGroups PolicyGroups
PolicyGroupEnvironments PolicyGroupEnvironments
PolicyGroups PolicyGroups
ProviderConfigurationLinks ProviderConfigurationLinks
ProviderConfigurationParameters ProviderConfigurationParameters
ProviderConfigurations ProviderConfigurations
Roles Roles
RunTriggers RunTriggers
Runs Runs
ServiceAccounts ServiceAccounts
Tags Tags
Teams Teams
Users Users
Variables Variables
VcsProviders VcsProviders
VcsRevisions VcsRevisions
Webhooks Webhooks
Workspaces Workspaces
WorkspaceTags WorkspaceTags
RunTriggers RunTriggers
Workspaces Workspaces
}

// NewClient creates a new Scalr API client.
Expand Down Expand Up @@ -211,35 +212,36 @@ func NewClient(cfg *Config) (*Client, error) {
}

// Create the services.
client.Accounts = &accounts{client: client}
client.AccessPolicies = &accessPolicies{client: client}
client.AccessTokens = &accessTokens{client: client}
client.AccountUsers = &accountUsers{client: client}
client.Accounts = &accounts{client: client}
client.AgentPoolTokens = &agentPoolTokens{client: client}
client.AgentPools = &agentPools{client: client}
client.ConfigurationVersions = &configurationVersions{client: client}
client.Endpoints = &endpoints{client: client}
client.Environments = &environments{client: client}
client.EnvironmentTags = &environmentTag{client: client}
client.Environments = &environments{client: client}
client.ModuleVersions = &moduleVersions{client: client}
client.Modules = &modules{client: client}
client.PolicyGroups = &policyGroups{client: client}
client.PolicyGroupEnvironments = &policyGroupEnvironment{client: client}
client.PolicyGroups = &policyGroups{client: client}
client.ProviderConfigurationLinks = &providerConfigurationLinks{client: client}
client.ProviderConfigurationParameters = &providerConfigurationParameters{client: client}
client.ProviderConfigurations = &providerConfigurations{client: client}
client.Roles = &roles{client: client}
client.RunTriggers = &runTriggers{client: client}
client.Runs = &runs{client: client}
client.ServiceAccounts = &serviceAccounts{client: client}
client.Tags = &tags{client: client}
client.Teams = &teams{client: client}
client.Users = &users{client: client}
client.Variables = &variables{client: client}
client.VcsProviders = &vcsProviders{client: client}
client.VcsRevisions = &vcsRevisions{client: client}
client.Webhooks = &webhooks{client: client}
client.Workspaces = &workspaces{client: client}
client.WorkspaceTags = &workspaceTag{client: client}
client.RunTriggers = &runTriggers{client: client}
client.ProviderConfigurations = &providerConfigurations{client: client}
client.ProviderConfigurationParameters = &providerConfigurationParameters{client: client}
client.ProviderConfigurationLinks = &providerConfigurationLinks{client: client}
client.Workspaces = &workspaces{client: client}
return client, nil
}

Expand Down
207 changes: 202 additions & 5 deletions service_account.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,206 @@
package scalr

import (
"context"
"errors"
"fmt"
"net/url"
"time"
)

// Compile-time proof of interface implementation.
var _ ServiceAccounts = (*serviceAccounts)(nil)

// ServiceAccounts describes all the service account related methods that the Scalr API supports.
type ServiceAccounts interface {
// List all the service accounts.
List(ctx context.Context, options ServiceAccountListOptions) (*ServiceAccountList, error)
// Create is used to create a new service account.
Create(ctx context.Context, options ServiceAccountCreateOptions) (*ServiceAccount, error)
// Read reads a service account by its ID.
Read(ctx context.Context, serviceAccountID string) (*ServiceAccount, error)
// Update existing service account by its ID.
Update(ctx context.Context, serviceAccountID string, options ServiceAccountUpdateOptions) (*ServiceAccount, error)
// Delete service account by its ID.
Delete(ctx context.Context, serviceAccountID string) error
}

// serviceAccounts implements ServiceAccounts.
type serviceAccounts struct {
client *Client
}

// ServiceAccountList represents a list of service accounts.
type ServiceAccountList struct {
*Pagination
Items []*ServiceAccount
}

// ServiceAccountStatus represents the status of service account.
type ServiceAccountStatus string

// List of available service account statuses.
const (
ServiceAccountStatusActive ServiceAccountStatus = "Active"
ServiceAccountStatusInactive ServiceAccountStatus = "Inactive"
)

type ServiceAccount struct {
ID string `jsonapi:"primary,service-accounts"`
Name string `jsonapi:"attr,name,omitempty"`
Email string `jsonapi:"attr,email,omitempty"`
Status string `jsonapi:"attr,status,omitempty"`
Account *Account `jsonapi:"relation,account,omitempty"`
ID string `jsonapi:"primary,service-accounts"`
Name string `jsonapi:"attr,name"`
Email string `jsonapi:"attr,email"`
Description string `jsonapi:"attr,description"`
Status ServiceAccountStatus `jsonapi:"attr,status"`
CreatedAt time.Time `jsonapi:"attr,created-at,iso8601"`

// Relations
Account *Account `jsonapi:"relation,account,omitempty"`
CreatedBy *User `jsonapi:"relation,created-by,omitempty"`
}

// ServiceAccountListOptions represents the options for listing service accounts.
type ServiceAccountListOptions struct {
ListOptions

Account *string `url:"filter[account],omitempty"`
Email *string `url:"filter[email],omitempty"`
Query *string `url:"query,omitempty"`
Include *string `url:"include,omitempty"`
}

// ServiceAccountCreateOptions represents the options for creating a new service account.
type ServiceAccountCreateOptions struct {
// For internal use only!
ID string `jsonapi:"primary,service-accounts"`

// The name of the service account, it must be unique within the account.
Name *string `jsonapi:"attr,name"`
Description *string `jsonapi:"attr,description,omitempty"`
Status *ServiceAccountStatus `jsonapi:"attr,status,omitempty"`
Account *Account `jsonapi:"relation,account"`
}

func (o ServiceAccountCreateOptions) valid() error {
if o.Account == nil {
return errors.New("account is required")
}
if !validStringID(&o.Account.ID) {
return errors.New("invalid value for account ID")
}
if o.Name == nil {
return errors.New("name is required")
}
return nil
}

// ServiceAccountUpdateOptions represents the options for updating a service account.
type ServiceAccountUpdateOptions struct {
// For internal use only!
ID string `jsonapi:"primary,service-accounts"`

Description *string `jsonapi:"attr,description,omitempty"`
Status *ServiceAccountStatus `jsonapi:"attr,status,omitempty"`
}

// Read a service account by its ID.
func (s *serviceAccounts) Read(ctx context.Context, serviceAccountID string) (*ServiceAccount, error) {
if !validStringID(&serviceAccountID) {
return nil, errors.New("invalid value for service account ID")
}

options := struct {
Include string `url:"include"`
}{
Include: "created-by",
}
u := fmt.Sprintf("service-accounts/%s", url.QueryEscape(serviceAccountID))
req, err := s.client.newRequest("GET", u, options)
if err != nil {
return nil, err
}

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

return sa, nil
}

// List all the service accounts.
func (s *serviceAccounts) List(ctx context.Context, options ServiceAccountListOptions) (*ServiceAccountList, error) {
req, err := s.client.newRequest("GET", "service-accounts", &options)
if err != nil {
return nil, err
}

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

return sal, nil
}

// Create is used to create a new service account.
func (s *serviceAccounts) Create(ctx context.Context, options ServiceAccountCreateOptions) (*ServiceAccount, 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", "service-accounts", &options)
if err != nil {
return nil, err
}

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

return sa, nil
}

// Update is used to update a service account.
func (s *serviceAccounts) Update(ctx context.Context, serviceAccountID string, options ServiceAccountUpdateOptions) (*ServiceAccount, error) {
if !validStringID(&serviceAccountID) {
return nil, errors.New("invalid value for service account ID")
}

// Make sure we don't send a user provided ID.
options.ID = ""

u := fmt.Sprintf("service-accounts/%s", url.QueryEscape(serviceAccountID))
req, err := s.client.newRequest("PATCH", u, &options)
if err != nil {
return nil, err
}

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

return sa, nil
}

// Delete service account by its ID.
func (s *serviceAccounts) Delete(ctx context.Context, serviceAccountID string) error {
if !validStringID(&serviceAccountID) {
return errors.New("invalid value for service account ID")
}

u := fmt.Sprintf("service-accounts/%s", url.QueryEscape(serviceAccountID))
req, err := s.client.newRequest("DELETE", u, nil)
if err != nil {
return err
}

return s.client.do(ctx, req, nil)
}
Loading

0 comments on commit 6329293

Please sign in to comment.