Skip to content

Commit

Permalink
no code provisioning in registry modules (#562)
Browse files Browse the repository at this point in the history
* add update operations for registry modules

* add no code properties to registry modules creation

* add changelog entry
  • Loading branch information
miguelhrocha committed Nov 15, 2022
1 parent 0f28f32 commit 6dcc99c
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -8,6 +8,7 @@

* Add OPA support to the Policy Set APIs by @mrinalirao [#575](https://github.com/hashicorp/go-tfe/pull/575)
* Add OPA support to the Policy APIs by @mrinalirao [#579](https://github.com/hashicorp/go-tfe/pull/579)
* Add support for enabling no-code provisioning in an existing or new `RegistryModule` by @miguelhrocha [#562](https://github.com/hashicorp/go-tfe/pull/562)
* Add Policy Evaluation and Policy Set Outcome APIs by @mrinalirao [#583](https://github.com/hashicorp/go-tfe/pull/583)
* Add OPA support to Task Stage APIs by @mrinalirao [#584](https://github.com/hashicorp/go-tfe/pull/584)

Expand Down
15 changes: 15 additions & 0 deletions mocks/registry_module_mocks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 56 additions & 0 deletions registry_module.go
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"log"
"net/http"
"net/url"
"strings"
)
Expand Down Expand Up @@ -40,6 +41,9 @@ type RegistryModules interface {
// Delete a specific registry module version
DeleteVersion(ctx context.Context, moduleID RegistryModuleID, version string) error

// Update properties of a registry module
Update(ctx context.Context, moduleID RegistryModuleID, options RegistryModuleUpdateOptions) (*RegistryModule, error)

// Upload Terraform configuration files for the provided registry module version. It
// requires a path to the configuration files on disk, which will be packaged by
// hashicorp/go-slug before being uploaded.
Expand Down Expand Up @@ -104,6 +108,7 @@ type RegistryModule struct {
Provider string `jsonapi:"attr,provider"`
RegistryName RegistryName `jsonapi:"attr,registry-name"`
Namespace string `jsonapi:"attr,namespace"`
NoCode bool `jsonapi:"attr,no-code"`
Permissions *RegistryModulePermissions `jsonapi:"attr,permissions"`
Status RegistryModuleStatus `jsonapi:"attr,status"`
VCSRepo *VCSRepo `jsonapi:"attr,vcs-repo"`
Expand Down Expand Up @@ -164,6 +169,9 @@ type RegistryModuleCreateOptions struct {
RegistryName RegistryName `jsonapi:"attr,registry-name,omitempty"`
// Optional: The namespace of this module. Required for public modules only.
Namespace string `jsonapi:"attr,namespace,omitempty"`
// Optional: If set to true the module is enabled for no-code provisioning.
// **Note: This field is still in BETA and subject to change.**
NoCode bool `jsonapi:"attr,no-code"`
}

// RegistryModuleCreateVersionOptions is used when creating a registry module version
Expand All @@ -189,6 +197,19 @@ type RegistryModuleCreateWithVCSConnectionOptions struct {
VCSRepo *RegistryModuleVCSRepoOptions `jsonapi:"attr,vcs-repo"`
}

// RegistryModuleCreateVersionOptions is used when updating a registry module
type RegistryModuleUpdateOptions struct {
// Type is a public field utilized by JSON:API to
// set the resource type via the field tag.
// It is not a user-defined value and does not need to be set.
// https://jsonapi.org/format/#crud-updating
Type string `jsonapi:"primary,registry-modules"`

// Optional: Flag to enable no-code provisioning for the whole module.
// **Note: This field is still in BETA and subject to change.**
NoCode *bool `jsonapi:"attr,no-code,omitempty"`
}

type RegistryModuleVCSRepoOptions struct {
Identifier *string `json:"identifier"` // Required
OAuthTokenID *string `json:"oauth-token-id"` // Required
Expand Down Expand Up @@ -265,6 +286,41 @@ func (r *registryModules) Create(ctx context.Context, organization string, optio
return rm, nil
}

func (r *registryModules) Update(ctx context.Context, moduleID RegistryModuleID, options RegistryModuleUpdateOptions) (*RegistryModule, error) {
if err := moduleID.valid(); err != nil {
return nil, err
}

if moduleID.RegistryName == "" {
log.Println("[WARN] Support for using the RegistryModuleID without RegistryName is deprecated as of release 1.5.0 and may be removed in a future version. The preferred method is to include the RegistryName in RegistryModuleID.")
moduleID.RegistryName = PrivateRegistry
}

if moduleID.RegistryName == PrivateRegistry && strings.TrimSpace(moduleID.Namespace) == "" {
log.Println("[WARN] Support for using the RegistryModuleID without Namespace is deprecated as of release 1.5.0 and may be removed in a future version. The preferred method is to include the Namespace in RegistryModuleID.")
moduleID.Namespace = moduleID.Organization
}

org := url.QueryEscape(moduleID.Organization)
registryName := url.QueryEscape(string(moduleID.RegistryName))
namespace := url.QueryEscape(moduleID.Namespace)
name := url.QueryEscape(moduleID.Name)
provider := url.QueryEscape(moduleID.Provider)
url := fmt.Sprintf("organizations/%s/registry-modules/%s/%s/%s/%s", org, registryName, namespace, name, provider)

req, err := r.client.NewRequest(http.MethodPatch, url, &options)
if err != nil {
return nil, err
}

rm := &RegistryModule{}
if err := req.Do(ctx, rm); err != nil {
return nil, err
}

return rm, nil
}

// CreateVersion creates a new registry module version
func (r *registryModules) CreateVersion(ctx context.Context, moduleID RegistryModuleID, options RegistryModuleCreateVersionOptions) (*RegistryModuleVersion, error) {
if err := moduleID.valid(); err != nil {
Expand Down
73 changes: 73 additions & 0 deletions registry_module_integration_test.go
Expand Up @@ -99,6 +99,7 @@ func TestRegistryModulesCreate(t *testing.T) {
assert.Equal(t, *options.Provider, rm.Provider)
assert.Equal(t, PrivateRegistry, rm.RegistryName)
assert.Equal(t, orgTest.Name, rm.Namespace)
assert.False(t, rm.NoCode, "no-code module attribute should be false by default")

assertRegistryModuleAttributes(t, rm)
})
Expand All @@ -116,6 +117,7 @@ func TestRegistryModulesCreate(t *testing.T) {
assert.Equal(t, *options.Provider, rm.Provider)
assert.Equal(t, options.RegistryName, rm.RegistryName)
assert.Equal(t, orgTest.Name, rm.Namespace)
assert.False(t, rm.NoCode, "no-code module attribute should be false by default")

assertRegistryModuleAttributes(t, rm)
})
Expand All @@ -134,6 +136,27 @@ func TestRegistryModulesCreate(t *testing.T) {
assert.Equal(t, *options.Provider, rm.Provider)
assert.Equal(t, options.RegistryName, rm.RegistryName)
assert.Equal(t, options.Namespace, rm.Namespace)
assert.False(t, rm.NoCode, "no-code module attribute should be false by default")

assertRegistryModuleAttributes(t, rm)
})

t.Run("with no-code attribute", func(t *testing.T) {
skipIfBeta(t)
options := RegistryModuleCreateOptions{
Name: String("iam"),
Provider: String("aws"),
NoCode: true,
RegistryName: PrivateRegistry,
}
rm, err := client.RegistryModules.Create(ctx, orgTest.Name, options)
require.NoError(t, err)
assert.NotEmpty(t, rm.ID)
assert.Equal(t, *options.Name, rm.Name)
assert.Equal(t, *options.Provider, rm.Provider)
assert.Equal(t, options.RegistryName, rm.RegistryName)
assert.Equal(t, orgTest.Name, rm.Namespace)
assert.Equal(t, options.NoCode, rm.NoCode)

assertRegistryModuleAttributes(t, rm)
})
Expand Down Expand Up @@ -224,6 +247,56 @@ func TestRegistryModulesCreate(t *testing.T) {
})
}

func TestRegistryModuleUpdate(t *testing.T) {
skipIfBeta(t)
client := testClient(t)
ctx := context.Background()

orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()

options := RegistryModuleCreateOptions{
Name: String("vault"),
Provider: String("aws"),
RegistryName: PublicRegistry,
Namespace: "hashicorp",
}
rm, err := client.RegistryModules.Create(ctx, orgTest.Name, options)
require.NoError(t, err)
assert.NotEmpty(t, rm.ID)

t.Run("enable no-code", func(t *testing.T) {
options := RegistryModuleUpdateOptions{
NoCode: Bool(true),
}
rm, err := client.RegistryModules.Update(ctx, RegistryModuleID{
Organization: orgTest.Name,
Name: "vault",
Provider: "aws",
Namespace: "hashicorp",
RegistryName: PublicRegistry,
}, options)
require.NoError(t, err)
assert.True(t, rm.NoCode)
})

t.Run("disable no-code", func(t *testing.T) {
options := RegistryModuleUpdateOptions{
NoCode: Bool(false),
}
rm, err := client.RegistryModules.Update(ctx, RegistryModuleID{
Organization: orgTest.Name,
Name: "vault",
Provider: "aws",
Namespace: "hashicorp",
RegistryName: PublicRegistry,
}, options)
require.NoError(t, err)
assert.False(t, rm.NoCode)
})

}

func TestRegistryModulesCreateVersion(t *testing.T) {
client := testClient(t)
ctx := context.Background()
Expand Down

0 comments on commit 6dcc99c

Please sign in to comment.