-
Notifications
You must be signed in to change notification settings - Fork 160
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added Tfe Terraform Version resource
This commit implements the Terraform version resource block "tfe_terraform_version" which allows practitioners to create and manage Terraform versions on TFE. This commit also outlines two tests for this resource. It generates a mock terraform version using a random version number and SHA. The URL attribute points to hashicorp.com since the TFC API doesn't download or verify that the zip exists when the resource is created. The basic test tests against the required parameters and the full test includes the optional parameters.
- Loading branch information
1 parent
72f4d0e
commit f25d34f
Showing
3 changed files
with
352 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |