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 Terraform Version Resource #400

Merged
merged 3 commits into from
Jan 5, 2022
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions tfe/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ func Provider() *schema.Provider {
"tfe_team_member": resourceTFETeamMember(),
"tfe_team_members": resourceTFETeamMembers(),
"tfe_team_token": resourceTFETeamToken(),
"tfe_terraform_version": resourceTFETerraformVersion(),
"tfe_workspace": resourceTFEWorkspace(),
"tfe_variable": resourceTFEVariable(),
},
Expand Down
136 changes: 136 additions & 0 deletions tfe/resource_tfe_terraform_version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package tfe

import (
"fmt"
"log"

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

func resourceTFETerraformVersion() *schema.Resource {
return &schema.Resource{
Create: resourceTFETerraformVersionCreate,
Read: resourceTFETerraformVersionRead,
Update: resourceTFETerraformVersionUpdate,
Delete: resourceTFETerraformVersionDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"version": {
Type: schema.TypeString,
Required: true,
},
"url": {
Type: schema.TypeString,
Required: true,
},
"sha": {
Type: schema.TypeString,
Required: true,
},
"official": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"enabled": {
Type: schema.TypeBool,
Optional: true,
Default: true,
},
"beta": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
},
}
}

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

opts := tfe.AdminTerraformVersionCreateOptions{
Version: tfe.String(d.Get("version").(string)),
URL: tfe.String(d.Get("url").(string)),
Sha: tfe.String(d.Get("sha").(string)),
Official: tfe.Bool(d.Get("official").(bool)),
Enabled: tfe.Bool(d.Get("enabled").(bool)),
Beta: tfe.Bool(d.Get("beta").(bool)),
}

log.Printf("[DEBUG] Create new Terraform version: %s", *opts.Version)
v, err := tfeClient.Admin.TerraformVersions.Create(ctx, opts)
if err != nil {
return fmt.Errorf("Error creating the new Terraform version %s: %v", *opts.Version, err)
}

d.SetId(v.ID)

return resourceTFETerraformVersionUpdate(d, meta)
}

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

log.Printf("[DEBUG] Read configuration of Terraform version: %s", d.Id())
v, err := tfeClient.Admin.TerraformVersions.Read(ctx, d.Id())
if err != nil {
if err == tfe.ErrResourceNotFound {
log.Printf("[DEBUG] Terraform version %s does no longer exist", d.Id())
d.SetId("")
return nil
}
return err
}

d.Set("version", v.Version)
d.Set("url", v.URL)
d.Set("sha", v.Sha)
d.Set("official", v.Official)
d.Set("enabled", v.Enabled)
d.Set("beta", v.Beta)

return nil
}

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

opts := tfe.AdminTerraformVersionUpdateOptions{
Version: tfe.String(d.Get("version").(string)),
URL: tfe.String(d.Get("url").(string)),
Sha: tfe.String(d.Get("sha").(string)),
Official: tfe.Bool(d.Get("official").(bool)),
Enabled: tfe.Bool(d.Get("enabled").(bool)),
Beta: tfe.Bool(d.Get("beta").(bool)),
}

log.Printf("[DEBUG] Update configuration of Terraform version: %s", d.Id())
v, err := tfeClient.Admin.TerraformVersions.Update(ctx, d.Id(), opts)
if err != nil {
return fmt.Errorf("Error updating Terraform version %s: %v", d.Id(), err)
}

d.SetId(v.ID)

return resourceTFETerraformVersionRead(d, meta)
}

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

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

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

import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"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 TestAccTFETerraformVersion_basic(t *testing.T) {
skipIfFreeOnly(t)

tfVersion := &tfe.AdminTerraformVersion{}
sha := genSha(t, "secret", "data")
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()
version := genVersion(rInt)

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckTFETerraformVersionDestroy,
Steps: []resource.TestStep{
{
Config: testAccTFETerraformVersion_basic(version, sha),
Check: resource.ComposeTestCheckFunc(
testAccCheckTFETerraformVersionExists("tfe_terraform_version.foobar", tfVersion),
testAccCheckTFETerraformVersionAttributesBasic(tfVersion, version, sha),
resource.TestCheckResourceAttr(
"tfe_terraform_version.foobar", "version", version),
resource.TestCheckResourceAttr(
"tfe_terraform_version.foobar", "url", "https://www.hashicorp.com"),
resource.TestCheckResourceAttr(
"tfe_terraform_version.foobar", "sha", sha),
),
},
},
})
}

func TestAccTFETerraformVersion_full(t *testing.T) {
skipIfFreeOnly(t)

tfVersion := &tfe.AdminTerraformVersion{}
sha := genSha(t, "secret", "data")
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()
version := genVersion(rInt)

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckTFETerraformVersionDestroy,
Steps: []resource.TestStep{
{
Config: testAccTFETerraformVersion_full(version, sha),
Check: resource.ComposeTestCheckFunc(
testAccCheckTFETerraformVersionExists("tfe_terraform_version.foobar", tfVersion),
testAccCheckTFETerraformVersionAttributesFull(tfVersion, version, sha),
resource.TestCheckResourceAttr(
"tfe_terraform_version.foobar", "version", version),
resource.TestCheckResourceAttr(
"tfe_terraform_version.foobar", "url", "https://www.hashicorp.com"),
resource.TestCheckResourceAttr(
"tfe_terraform_version.foobar", "sha", sha),
resource.TestCheckResourceAttr(
"tfe_terraform_version.foobar", "official", "false"),
resource.TestCheckResourceAttr(
"tfe_terraform_version.foobar", "enabled", "true"),
resource.TestCheckResourceAttr(
"tfe_terraform_version.foobar", "beta", "true"),
),
},
},
})
}

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

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

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

_, err := tfeClient.Admin.TerraformVersions.Read(ctx, rs.Primary.ID)
if err == nil {
return fmt.Errorf("Terraform version %s still exists", rs.Primary.ID)
}
}

return nil
}

func testAccCheckTFETerraformVersionExists(n string, tfVersion *tfe.AdminTerraformVersion) 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")
}

v, err := tfeClient.Admin.TerraformVersions.Read(ctx, rs.Primary.ID)
if err != nil {
return err
}

if v.ID != rs.Primary.ID {
return fmt.Errorf("Terraform version not found")
}

*tfVersion = *v

return nil
}
}

func testAccCheckTFETerraformVersionAttributesBasic(tfVersion *tfe.AdminTerraformVersion, version string, sha string) resource.TestCheckFunc {
return func(s *terraform.State) error {
if tfVersion.URL != "https://www.hashicorp.com" {
return fmt.Errorf("Bad URL: %s", tfVersion.URL)
}

if tfVersion.Version != version {
return fmt.Errorf("Bad version: %s", tfVersion.Version)
}

if tfVersion.Sha != sha {
return fmt.Errorf("Bad value for Sha: %v", tfVersion.Sha)
}

return nil
}
}

func testAccCheckTFETerraformVersionAttributesFull(tfVersion *tfe.AdminTerraformVersion, version string, sha string) resource.TestCheckFunc {
return func(s *terraform.State) error {
if tfVersion.URL != "https://www.hashicorp.com" {
return fmt.Errorf("Bad URL: %s", tfVersion.URL)
}

if tfVersion.Version != version {
return fmt.Errorf("Bad version: %s", tfVersion.Version)
}

if tfVersion.Sha != sha {
return fmt.Errorf("Bad value for Sha: %v", tfVersion.Sha)
}

if tfVersion.Official != false {
return fmt.Errorf("Bad value for official: %t", tfVersion.Official)
}

if tfVersion.Enabled != true {
return fmt.Errorf("Bad value for enabled: %t", tfVersion.Enabled)
}

if tfVersion.Beta != true {
return fmt.Errorf("Bad value for beta: %t", tfVersion.Beta)
}

return nil
}
}

func testAccTFETerraformVersion_basic(version string, sha string) string {
return fmt.Sprintf(`
resource "tfe_terraform_version" "foobar" {
version = "%s"
url = "https://www.hashicorp.com"
sha = "%s"
}`, version, sha)
}

func testAccTFETerraformVersion_full(version string, sha string) string {
return fmt.Sprintf(`
resource "tfe_terraform_version" "foobar" {
version = "%s"
url = "https://www.hashicorp.com"
sha = "%s"
official = false
enabled = true
beta = true
}`, version, sha)
}

// Helper functions
func genSha(t *testing.T, secret, data string) string {
h := hmac.New(sha256.New, []byte(secret))
_, err := h.Write([]byte(data))
if err != nil {
t.Fatalf("error writing hmac: %s", err)
}

sha := hex.EncodeToString(h.Sum(nil))
return sha
}

func genVersion(rInt int) string {
return fmt.Sprintf("%d.%d.%d", rInt, rInt, rInt)
}
Loading