Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new resource tfe_agent_token #259

Merged
merged 5 commits into from
Jan 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
## 0.24.0 (Unreleased)
FEATURES:
* **New Resource:** r/tfe_agent_token ([#259](https://github.com/hashicorp/terraform-provider-tfe/pull/259))

BREAKING CHANGES:
* d/tfe_workspace_ids: Changed `ids` attribute to return immutable workspace IDs in the format `ws-<RANDOM STRING>` ([#253](https://github.com/hashicorp/terraform-provider-tfe/pull/253))
* r/tfe_notification_configuration: Removed deprecated `workspace_external_id` attribute, preferring `workspace_id` instead ([#253](https://github.com/hashicorp/terraform-provider-tfe/pull/253))
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/hashicorp/terraform-provider-tfe
go 1.14

require (
github.com/hashicorp/go-tfe v0.11.1
github.com/hashicorp/go-tfe v0.12.0
github.com/hashicorp/go-version v1.2.1
github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce
github.com/hashicorp/terraform-plugin-sdk/v2 v2.3.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,8 @@ github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhE
github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
github.com/hashicorp/go-slug v0.4.1 h1:/jAo8dNuLgSImoLXaX7Od7QB4TfYCVPam+OpAt5bZqc=
github.com/hashicorp/go-slug v0.4.1/go.mod h1:I5tq5Lv0E2xcNXNkmx7BSfzi1PsJ2cNjs3cC3LwyhK8=
github.com/hashicorp/go-tfe v0.11.1 h1:BD0HlSTcptjHkIYLgZ2+mgfyfXRBXnkkHoJpzWP4vkI=
github.com/hashicorp/go-tfe v0.11.1/go.mod h1:XAV72S4O1iP8BDaqiaPLmL2B4EE6almocnOn8E8stHc=
github.com/hashicorp/go-tfe v0.12.0 h1:teL523WPxwYzL5Gjc2QFxExndrMfWY4BXS2/olVpULM=
github.com/hashicorp/go-tfe v0.12.0/go.mod h1:oT0AG5u/ROzWiw8JZFLDY6FLh6AZnJIG0Ahhvp10txg=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
Expand Down
1 change: 1 addition & 0 deletions tfe/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ func Provider() *schema.Provider {

ResourcesMap: map[string]*schema.Resource{
"tfe_agent_pool": resourceTFEAgentPool(),
"tfe_agent_token": resourceTFEAgentToken(),
"tfe_notification_configuration": resourceTFENotificationConfiguration(),
"tfe_oauth_client": resourceTFEOAuthClient(),
"tfe_organization": resourceTFEOrganization(),
Expand Down
100 changes: 100 additions & 0 deletions tfe/resource_tfe_agent_token.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package tfe

import (
"fmt"
"log"

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

func resourceTFEAgentToken() *schema.Resource {
return &schema.Resource{
Create: resourceTFEAgentTokenCreate,
Read: resourceTFEAgentTokenRead,
Delete: resourceTFEAgentTokenDelete,

Schema: map[string]*schema.Schema{
"agent_pool_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"description": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"token": {
Type: schema.TypeString,
Computed: true,
Sensitive: true,
},
},
}
}

func resourceTFEAgentTokenCreate(d *schema.ResourceData, meta interface{}) error {
tfeClient := meta.(*tfe.Client)

// Get the agent pool ID
agentPoolID := d.Get("agent_pool_id").(string)

// Get the description.
description := d.Get("description").(string)

// Create a new options struct
options := tfe.AgentTokenGenerateOptions{
Description: tfe.String(description),
}

log.Printf("[DEBUG] Create new agent token for agent pool ID: %s", agentPoolID)
agentToken, err := tfeClient.AgentTokens.Generate(ctx, agentPoolID, options)
if err != nil {
return fmt.Errorf("Error creating agent token for agent pool ID %s: %v", agentPoolID, err)

}

d.SetId(agentToken.ID)

// We need to set this here in the create function as this value will
// only be returned once during the creation of the token.
d.Set("token", agentToken.Token)

return resourceTFEAgentTokenRead(d, meta)
}

func resourceTFEAgentTokenRead(d *schema.ResourceData, meta interface{}) error {
tfeClient := meta.(*tfe.Client)

log.Printf("[DEBUG] Read configuration of agent token: %s", d.Id())
agentToken, err := tfeClient.AgentTokens.Read(ctx, d.Id())
if err != nil {
if err == tfe.ErrResourceNotFound {
log.Printf("[DEBUG] agent token %s no longer exists", d.Id())
d.SetId("")
return nil
}
return fmt.Errorf("Error reading configuration of agent token %s: %v", d.Id(), err)
}

// Update the config
d.Set("description", agentToken.Description)

return nil
}

func resourceTFEAgentTokenDelete(d *schema.ResourceData, meta interface{}) error {
tfeClient := meta.(*tfe.Client)

log.Printf("[DEBUG] Delete agent token: %s", d.Id())
err := tfeClient.AgentTokens.Delete(ctx, d.Id())
if err != nil {
if err == tfe.ErrResourceNotFound {
return nil
}
return fmt.Errorf("Error deleting agent token %s: %v", d.Id(), err)
}

return nil
}
113 changes: 113 additions & 0 deletions tfe/resource_tfe_agent_token_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package tfe

import (
"fmt"
"math/rand"
"testing"
"time"

tfe "github.com/hashicorp/go-tfe"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func TestAccTFEAgentToken_basic(t *testing.T) {
agentToken := &tfe.AgentToken{}
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckTFEAgentTokenDestroy,
Steps: []resource.TestStep{
{
Config: testAccTFEAgentToken_basic(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckTFEAgentTokenExists(
"tfe_agent_token.foobar", agentToken),
testAccCheckTFEAgentTokenAttributes(agentToken),
resource.TestCheckResourceAttr(
"tfe_agent_token.foobar", "description", "agent-token-test"),
),
},
},
})
}

func testAccCheckTFEAgentTokenExists(
n string, agentToken *tfe.AgentToken) resource.TestCheckFunc {
return func(s *terraform.State) error {
tfeClient := testAccProvider.Meta().(*tfe.Client)

rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}

if rs.Primary.ID == "" {
return fmt.Errorf("No instance ID is set")
}

sk, err := tfeClient.AgentTokens.Read(ctx, rs.Primary.ID)
if err != nil {
return err
}

if sk == nil {
return fmt.Errorf("agent token not found")
}

*agentToken = *sk

return nil
}
}

func testAccCheckTFEAgentTokenAttributes(
agentToken *tfe.AgentToken) resource.TestCheckFunc {
return func(s *terraform.State) error {
if agentToken.Description != "agent-token-test" {
return fmt.Errorf("Bad name: %s", agentToken.Description)
}
return nil
}
}

func testAccCheckTFEAgentTokenDestroy(s *terraform.State) error {
tfeClient := testAccProvider.Meta().(*tfe.Client)

for _, rs := range s.RootModule().Resources {
if rs.Type != "tfe_agent_token" {
continue
}

if rs.Primary.ID == "" {
return fmt.Errorf("No instance ID is set")
}

_, err := tfeClient.AgentTokens.Read(ctx, rs.Primary.ID)
if err == nil {
return fmt.Errorf("agent token %s still exists", rs.Primary.ID)
}
}

return nil
}

func testAccTFEAgentToken_basic(rInt int) string {
return fmt.Sprintf(`
resource "tfe_organization" "foobar" {
name = "tst-terraform-%d"
email = "[email protected]"
}

resource "tfe_agent_pool" "foobar" {
name = "agent-pool-test"
organization = tfe_organization.foobar.id
}

resource "tfe_agent_token" "foobar" {
agent_pool_id = tfe_agent_pool.foobar.id
description = "agent-token-test"
}`, rInt)
}
50 changes: 50 additions & 0 deletions website/docs/r/agent_token.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
layout: "tfe"
page_title: "Terraform Enterprise: tfe_agent_token"
sidebar_current: "docs-resource-tfe-agent-token"
description: |-
Manages agent tokens
---

# tfe_agent_token

Each agent pool has its own set of tokens which are not shared across pools.
These tokens allow agents to communicate securely with Terraform Cloud.

~> **NOTE:** This resource requires using the provider with Terraform Cloud and a Terraform Cloud
for Business account.
[Learn more about Terraform Cloud pricing here](https://www.hashicorp.com/products/terraform/pricing).

## Example Usage

Basic usage:

```hcl
resource "tfe_organization" "test-organization" {
name = "my-org-name"
email = "[email protected]"
}

resource "tfe_agent_pool" "test-agent-pool" {
name = "my-agent-pool-name"
organization = tfe_organization.test-organization.id
}

resource "tfe_agent_token" "test-agent-token" {
agent_pool_id = tfe_agent_pool.test-agent-pool.id
description = "my-agent-token-name"
}
```

## Argument Reference

The following arguments are supported:

* `agent_pool_id` - (Required) ID of the agent pool.
* `description` - (Required) Description of the agent token.

## Attributes Reference

* `id` - The ID of the agent token.
* `description` - The description of agent token.
* `token` - The generated token.
4 changes: 4 additions & 0 deletions website/tfe.erb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@
<a href="/docs/providers/tfe/r/agent_pool.html">tfe_agent_pool</a>
</li>

<li<%= sidebar_current("docs-resource-tfe-agent-token") %>>
<a href="/docs/providers/tfe/r/agent_token.html">tfe_agent_token</a>
</li>

<li<%= sidebar_current("docs-resource-tfe-notification-configuration") %>>
<a href="/docs/providers/tfe/r/notification_configuration.html">tfe_notification_configuration</a>
</li>
Expand Down