Skip to content

Commit

Permalink
Introduce no-code modules in registry modules (hashicorp#673)
Browse files Browse the repository at this point in the history
* create and update no-code module

* update documentation with no_code attribute

* update CHANGELOG

* upgrade go-tfe to v1.13.0
  • Loading branch information
miguelhrocha committed Nov 18, 2022
1 parent 06e2f6c commit 8fc8adb
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
@@ -1,6 +1,7 @@
## Unreleased

FEATURES:
* r/registry_module: Adds `no_code` field. ([#673](https://github.com/hashicorp/terraform-provider-tfe/pull/673))
* r/tfe_organization: Add `allow_force_delete_workspaces` attribute to set whether admins are permitted to delete workspaces with resource under management. ([#661](https://github.com/hashicorp/terraform-provider-tfe/pull/661))
* r/tfe_workspace: Add `force_delete` attribute to set whether workspaces will be force deleted when removed through the provider. Otherwise, they will be safe deleted. ([#675](https://github.com/hashicorp/terraform-provider-tfe/pull/675))

Expand Down
42 changes: 42 additions & 0 deletions tfe/resource_tfe_registry_module.go
Expand Up @@ -17,6 +17,7 @@ func resourceTFERegistryModule() *schema.Resource {
return &schema.Resource{
Create: resourceTFERegistryModuleCreate,
Read: resourceTFERegistryModuleRead,
Update: resourceTFERegistryModuleUpdate,
Delete: resourceTFERegistryModuleDelete,
Importer: &schema.ResourceImporter{
StateContext: resourceTFERegistryModuleImporter,
Expand Down Expand Up @@ -76,6 +77,11 @@ func resourceTFERegistryModule() *schema.Resource {
ForceNew: true,
RequiredWith: []string{"registry_name"},
},
"no_code": {
Type: schema.TypeBool,
Optional: true,
Computed: true,
},
"registry_name": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -118,6 +124,7 @@ func resourceTFERegistryModuleCreateWithoutVCS(meta interface{}, d *schema.Resou
options := tfe.RegistryModuleCreateOptions{
Name: tfe.String(d.Get("name").(string)),
Provider: tfe.String(d.Get("module_provider").(string)),
NoCode: d.Get("no_code").(bool),
}

if registryName, ok := d.GetOk("registry_name"); ok {
Expand Down Expand Up @@ -190,6 +197,40 @@ func resourceTFERegistryModuleCreate(d *schema.ResourceData, meta interface{}) e
return resourceTFERegistryModuleRead(d, meta)
}

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

options := tfe.RegistryModuleUpdateOptions{
NoCode: tfe.Bool(d.Get("no_code").(bool)),
}
var registryModule *tfe.RegistryModule
var err error

rmID := tfe.RegistryModuleID{
Organization: d.Get("organization").(string),
Name: d.Get("name").(string),
Provider: d.Get("module_provider").(string),
Namespace: d.Get("namespace").(string),
RegistryName: tfe.RegistryName(d.Get("registry_name").(string)),
}

err = resource.Retry(time.Duration(5)*time.Minute, func() *resource.RetryError {
registryModule, err = tfeClient.RegistryModules.Update(ctx, rmID, options)
if err != nil {
return resource.RetryableError(err)
}
return nil
})

if err != nil {
return fmt.Errorf("Error while waiting for module %s/%s to be updated: %w", registryModule.Organization.Name, registryModule.Name, err)
}

d.SetId(registryModule.ID)

return resourceTFERegistryModuleRead(d, meta)
}

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

Expand Down Expand Up @@ -221,6 +262,7 @@ func resourceTFERegistryModuleRead(d *schema.ResourceData, meta interface{}) err
d.Set("organization", registryModule.Organization.Name)
d.Set("namespace", registryModule.Namespace)
d.Set("registry_name", registryModule.RegistryName)
d.Set("no_code", registryModule.NoCode)

// Set VCS repo options.
var vcsRepo []interface{}
Expand Down
71 changes: 71 additions & 0 deletions tfe/resource_tfe_registry_module_test.go
Expand Up @@ -236,6 +236,59 @@ func TestAccTFERegistryModule_publicRegistryModule(t *testing.T) {
})
}

func TestAccTFERegistryModule_noCodeModule(t *testing.T) {
registryModule := &tfe.RegistryModule{}
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()
orgName := fmt.Sprintf("tst-terraform-%d", rInt)

expectedRegistryModuleAttributes := &tfe.RegistryModule{
Name: "vpc",
Provider: "aws",
RegistryName: tfe.PublicRegistry,
Namespace: "terraform-aws-modules",
Organization: &tfe.Organization{Name: orgName},
NoCode: true,
}

resource.Test(t, resource.TestCase{
IsUnitTest: true,
PreCheck: func() {
testAccPreCheck(t)
},
Providers: testAccProviders,
CheckDestroy: testAccCheckTFERegistryModuleDestroy,
Steps: []resource.TestStep{
{
Config: testAccTFERegistryModule_NoCode(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckTFERegistryModuleExists(
"tfe_registry_module.foobar",
tfe.RegistryModuleID{
Organization: orgName,
Name: expectedRegistryModuleAttributes.Name,
Provider: expectedRegistryModuleAttributes.Provider,
RegistryName: expectedRegistryModuleAttributes.RegistryName,
Namespace: expectedRegistryModuleAttributes.Namespace,
}, registryModule),
testAccCheckTFERegistryModuleAttributes(registryModule, expectedRegistryModuleAttributes),
resource.TestCheckResourceAttr(
"tfe_registry_module.foobar", "organization", orgName),
resource.TestCheckResourceAttr(
"tfe_registry_module.foobar", "name", expectedRegistryModuleAttributes.Name),
resource.TestCheckResourceAttr(
"tfe_registry_module.foobar", "module_provider", expectedRegistryModuleAttributes.Provider),
resource.TestCheckResourceAttr(
"tfe_registry_module.foobar", "namespace", expectedRegistryModuleAttributes.Namespace),
resource.TestCheckResourceAttr(
"tfe_registry_module.foobar", "registry_name", string(expectedRegistryModuleAttributes.RegistryName)),
resource.TestCheckResourceAttr(
"tfe_registry_module.foobar", "no_code", fmt.Sprint(expectedRegistryModuleAttributes.NoCode)),
),
},
},
})
}

func TestAccTFERegistryModuleImport_vcsPrivateRMDeprecatedFormat(t *testing.T) {
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()

Expand Down Expand Up @@ -674,6 +727,24 @@ resource "tfe_registry_module" "foobar" {
rInt)
}

func testAccTFERegistryModule_NoCode(rInt int) string {
return fmt.Sprintf(`
resource "tfe_organization" "foobar" {
name = "tst-terraform-%d"
email = "admin@company.com"
}
resource "tfe_registry_module" "foobar" {
organization = tfe_organization.foobar.id
namespace = "terraform-aws-modules"
module_provider = "aws"
name = "vpc"
registry_name = "public"
no_code = true
}`,
rInt)
}

func testAccTFERegistryModule_invalidWithBothVCSRepoAndModuleProvider() string {
return `
resource "tfe_registry_module" "foobar" {
Expand Down
20 changes: 20 additions & 0 deletions website/docs/r/registry_module.html.markdown
Expand Up @@ -70,6 +70,24 @@ resource "tfe_registry_module" "test-public-registry-module" {
}
```

Create no-code provisioning registry module:

```hcl
resource "tfe_organization" "test-organization" {
name = "my-org-name"
email = "admin@company.com"
}
resource "tfe_registry_module" "test-no-code-provisioning-registry-module" {
organization = tfe_organization.test-organization.name
namespace = "terraform-aws-modules"
module_provider = "aws"
name = "vpc"
registry_name = "public"
no_code = true
}
```

## Argument Reference

The following arguments are supported:
Expand All @@ -81,6 +99,7 @@ The following arguments are supported:
* `organization` - (Optional) The name of the organization associated with the registry module. It must be set if `module_provider` is used.
* `namespace` - (Optional) The namespace of a public registry module. It can be used if `module_provider` is set and `registry_name` is public.
* `registry_name` - (Optional) Whether the registry module is private or public. It can be used if `module_provider` is set.
* `no_code` - (Optional) Whether the registry module is enabled for [no-code provisioning](https://learn.hashicorp.com/tutorials/terraform/no-code-provisioning). Defaults to `false`.

The `vcs_repo` block supports:

Expand All @@ -101,6 +120,7 @@ The `vcs_repo` block supports:
* `organization` - The name of the organization associated with the registry module.
* `namespace` - The namespace of the module. For private modules this is the name of the organization that owns the module.
* `registry_name` - The registry name of the registry module depicting whether the registry module is private or public.
* `no_code` - The property that will enable or disable a module as no-code provisioning ready.

## Import

Expand Down

0 comments on commit 8fc8adb

Please sign in to comment.