Skip to content

Commit

Permalink
SCALRCORE-21783 Add scalr_service_account_token resource
Browse files Browse the repository at this point in the history
[API_BRANCH]
  • Loading branch information
petroprotsakh committed Jan 7, 2023
1 parent c81e4fc commit 76f6889
Show file tree
Hide file tree
Showing 11 changed files with 290 additions and 24 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **New data source:** `scalr_current_account` ([#199](https://github.com/Scalr/terraform-provider-scalr/pull/199))
- **New data source:** `scalr_service_account` ([#200](https://github.com/Scalr/terraform-provider-scalr/pull/200))
- **New resource:** `scalr_service_account` ([#200](https://github.com/Scalr/terraform-provider-scalr/pull/200))
- **New resource:** `scalr_service_account_token` ([#201](https://github.com/Scalr/terraform-provider-scalr/pull/201))

### Changed

Expand Down
8 changes: 0 additions & 8 deletions docs/resources/scalr_agent_pool_token.md
Expand Up @@ -25,11 +25,3 @@ All arguments plus:

* `id` - The ID of the token.
* `token` - The token of the agent pool.

## Import

To import agent pool's token use token ID as the import ID. For example:

```shell
terraform import scalr_agent_pool_token.default at-xxxxxxxxx
```
27 changes: 27 additions & 0 deletions docs/resources/scalr_service_account_token.md
@@ -0,0 +1,27 @@

# Resource `scalr_service_account_token`

Manage the state of service account's tokens in Scalr. Create, update and destroy.

## Example Usage

Basic usage:

```hcl
resource "scalr_service_account_token" "default" {
service_account_id = "sa-xxxxxxx"
description = "Some description"
}
```

## Argument Reference

* `service_account_id` - (Required) ID of the service account.
* `description` - (Optional) Description of the token.

## Attribute Reference

All arguments plus:

* `id` - The ID of the token.
* `token` - (Sensitive) The token of the service account.
2 changes: 1 addition & 1 deletion go.mod
Expand Up @@ -5,7 +5,7 @@ require (
github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce
github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.1
github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734
github.com/scalr/go-scalr v0.0.0-20230105224441-a859777b36b2
github.com/scalr/go-scalr v0.0.0-20230107114706-a9e0dbf61816
)

require (
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Expand Up @@ -242,8 +242,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/scalr/go-scalr v0.0.0-20230105224441-a859777b36b2 h1:5sumUNoyVDmqvZ9Jx/oGWz9SBsTeeILAhrDr7DfN72s=
github.com/scalr/go-scalr v0.0.0-20230105224441-a859777b36b2/go.mod h1:p34SHb25YRvbgft7SUjSDYESeoQhWzAlxGXId/BbaSE=
github.com/scalr/go-scalr v0.0.0-20230107114706-a9e0dbf61816 h1:Gyvkihl28LfX6U525N3HhIQ5CO5hpO+GGJqI1prlhlA=
github.com/scalr/go-scalr v0.0.0-20230107114706-a9e0dbf61816/go.mod h1:p34SHb25YRvbgft7SUjSDYESeoQhWzAlxGXId/BbaSE=
github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
Expand Down
1 change: 1 addition & 0 deletions scalr/provider.go
Expand Up @@ -97,6 +97,7 @@ func Provider() *schema.Provider {
"scalr_role": resourceScalrRole(),
"scalr_run_trigger": resourceScalrRunTrigger(),
"scalr_service_account": resourceScalrServiceAccount(),
"scalr_service_account_token": resourceScalrServiceAccountToken(),
"scalr_tag": resourceScalrTag(),
"scalr_variable": resourceScalrVariable(),
"scalr_vcs_provider": resourceScalrVcsProvider(),
Expand Down
4 changes: 2 additions & 2 deletions scalr/resource_scalr_agent_pool_token.go
Expand Up @@ -43,7 +43,7 @@ func resourceScalrAgentPoolTokenCreate(ctx context.Context, d *schema.ResourceDa
poolID := d.Get("agent_pool_id").(string)

// Create a new options struct
options := scalr.AgentPoolTokenCreateOptions{}
options := scalr.AccessTokenCreateOptions{}

if desc, ok := d.GetOk("description"); ok {
options.Description = scalr.String(desc.(string))
Expand Down Expand Up @@ -73,7 +73,7 @@ func resourceScalrAgentPoolTokenRead(ctx context.Context, d *schema.ResourceData
}

log.Printf("[DEBUG] Read configuration of agent pool token: %s", id)
options := scalr.AgentPoolTokenListOptions{}
options := scalr.AccessTokenListOptions{}

for {
tokensList, err := scalrClient.AgentPoolTokens.List(ctx, poolID, options)
Expand Down
14 changes: 7 additions & 7 deletions scalr/resource_scalr_agent_pool_token_test.go
Expand Up @@ -12,7 +12,7 @@ import (
)

func TestAccScalrAgentPoolToken_basic(t *testing.T) {
token := &scalr.AgentPoolToken{}
token := &scalr.AccessToken{}

var pool scalr.AgentPool
if isAccTest() {
Expand Down Expand Up @@ -44,7 +44,7 @@ func TestAccScalrAgentPoolToken_changed_outside(t *testing.T) {
pool = createPool(t)
defer deletePool(t, pool)
}
token := &scalr.AgentPoolToken{}
token := &scalr.AccessToken{}

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Expand Down Expand Up @@ -78,7 +78,7 @@ func TestAccScalrAgentPoolToken_update(t *testing.T) {
pool = createPool(t)
defer deletePool(t, pool)
}
token := &scalr.AgentPoolToken{}
token := &scalr.AccessToken{}

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Expand All @@ -104,7 +104,7 @@ func TestAccScalrAgentPoolToken_update(t *testing.T) {
})
}

func testAccCheckScalrAgentPoolTokenExists(resId string, pool scalr.AgentPool, token *scalr.AgentPoolToken) resource.TestCheckFunc {
func testAccCheckScalrAgentPoolTokenExists(resId string, pool scalr.AgentPool, token *scalr.AccessToken) resource.TestCheckFunc {
return func(s *terraform.State) error {
scalrClient := testAccProvider.Meta().(*scalr.Client)

Expand All @@ -118,7 +118,7 @@ func testAccCheckScalrAgentPoolTokenExists(resId string, pool scalr.AgentPool, t
}

// Get the token
l, err := scalrClient.AgentPoolTokens.List(ctx, pool.ID, scalr.AgentPoolTokenListOptions{})
l, err := scalrClient.AgentPoolTokens.List(ctx, pool.ID, scalr.AccessTokenListOptions{})
if err != nil {
return err
}
Expand All @@ -136,7 +136,7 @@ func testAccCheckScalrAgentPoolTokenExists(resId string, pool scalr.AgentPool, t
}
}

func testAccCheckScalrAgentPoolTokenChangedOutside(token *scalr.AgentPoolToken) func() {
func testAccCheckScalrAgentPoolTokenChangedOutside(token *scalr.AccessToken) func() {
return func() {
scalrClient := testAccProvider.Meta().(*scalr.Client)

Expand Down Expand Up @@ -197,7 +197,7 @@ func testAccCheckScalrAgentPoolTokenDestroy(s *terraform.State) error {
poolID := rs.Primary.Attributes["agent_pool_id"]

// the agent pool must be deleted along with token
l, _ := scalrClient.AgentPoolTokens.List(ctx, poolID, scalr.AgentPoolTokenListOptions{})
l, _ := scalrClient.AgentPoolTokens.List(ctx, poolID, scalr.AccessTokenListOptions{})
if len(l.Items) > 0 {
return fmt.Errorf("AgentPoolToken %s still exists", rs.Primary.ID)
}
Expand Down
6 changes: 2 additions & 4 deletions scalr/resource_scalr_service_account_test.go
Expand Up @@ -72,10 +72,8 @@ func TestAccScalrServiceAccount_update(t *testing.T) {
Steps: []resource.TestStep{
{
Config: testAccScalrServiceAccountBasic(rInt),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"scalr_service_account.test", "name", fmt.Sprintf("test-sa-%d", rInt),
),
Check: resource.TestCheckResourceAttr(
"scalr_service_account.test", "name", fmt.Sprintf("test-sa-%d", rInt),
),
},
{
Expand Down
146 changes: 146 additions & 0 deletions scalr/resource_scalr_service_account_token.go
@@ -0,0 +1,146 @@
package scalr

import (
"context"
"errors"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"log"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/scalr/go-scalr"
)

func resourceScalrServiceAccountToken() *schema.Resource {
return &schema.Resource{
CreateContext: resourceScalrServiceAccountTokenCreate,
ReadContext: resourceScalrServiceAccountTokenRead,
UpdateContext: resourceScalrServiceAccountTokenUpdate,
DeleteContext: resourceScalrServiceAccountTokenDelete,
Schema: map[string]*schema.Schema{
"service_account_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"description": {
Type: schema.TypeString,
Optional: true,
},
"token": {
Type: schema.TypeString,
Computed: true,
Sensitive: true,
},
},
}
}

func resourceScalrServiceAccountTokenCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
scalrClient := meta.(*scalr.Client)

saID := d.Get("service_account_id").(string)

options := scalr.AccessTokenCreateOptions{}
if desc, ok := d.GetOk("description"); ok {
options.Description = scalr.String(desc.(string))
}

log.Printf("[DEBUG] Create access token for service account: %s", saID)
at, err := scalrClient.ServiceAccountTokens.Create(ctx, saID, options)
if err != nil {
return diag.Errorf(
"Error creating access token for service account %s: %v", saID, err)
}

// the token is returned from API only while creating
_ = d.Set("token", at.Token)

d.SetId(at.ID)

return resourceScalrServiceAccountTokenRead(ctx, d, meta)
}

func resourceScalrServiceAccountTokenRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
scalrClient := meta.(*scalr.Client)
id := d.Id()
saID := d.Get("service_account_id").(string)

if saID == "" {
return diag.Errorf("This resource does not support import")
}

log.Printf("[DEBUG] Read service account token: %s", id)
options := scalr.AccessTokenListOptions{}

for {
atl, err := scalrClient.ServiceAccountTokens.List(ctx, saID, options)

if err != nil {
if errors.Is(err, scalr.ErrResourceNotFound) {
log.Printf("[DEBUG] service account %s not found", saID)
d.SetId("")
return nil
}
return diag.Errorf("Error reading service account token %s: %v", id, err)
}

for _, at := range atl.Items {
if at.ID == id {
_ = d.Set("description", at.Description)
return nil
}
}

// Exit the loop when we've seen all pages.
if atl.CurrentPage >= atl.TotalPages {
break
}

// Update the page number to get the next page.
options.PageNumber = atl.NextPage
}

// the token has been deleted
d.SetId("")
return nil
}

func resourceScalrServiceAccountTokenUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
scalrClient := meta.(*scalr.Client)

id := d.Id()

if d.HasChange("description") {
desc := d.Get("description").(string)

options := scalr.AccessTokenUpdateOptions{
Description: scalr.String(desc),
}

log.Printf("[DEBUG] Update service account access token %s", id)
_, err := scalrClient.AccessTokens.Update(ctx, id, options)
if err != nil {
return diag.Errorf(
"Error updating service account access token %s: %v", id, err)
}
}

return resourceScalrServiceAccountTokenRead(ctx, d, meta)
}

func resourceScalrServiceAccountTokenDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
scalrClient := meta.(*scalr.Client)
id := d.Id()

log.Printf("[DEBUG] Delete service account access token %s", id)
err := scalrClient.AccessTokens.Delete(ctx, id)
if err != nil {
if errors.Is(err, scalr.ErrResourceNotFound) {
return nil
}
return diag.Errorf(
"Error deleting service account access token %s: %v", id, err)
}

return nil
}

0 comments on commit 76f6889

Please sign in to comment.