Skip to content

Commit

Permalink
Re-work plugin ID to allow names with slashes, fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
tomhjp committed Apr 30, 2024
1 parent 713c102 commit 77f35a4
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 47 deletions.
48 changes: 33 additions & 15 deletions vault/resource_plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"context"
"fmt"
"log"
"strings"
"regexp"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
Expand All @@ -27,6 +27,34 @@ const (
fieldRuntime = "runtime"
)

var (
// Version regex is intentionally loose, its main purpose is to disallow
// slashes so they can be used to delineate from the name. Version segment
// is optional.
pluginIDRegex = regexp.MustCompile(`^(auth|secret|database)(?:/version/([0-9a-zA-Z.-]+?))?/name/(.+)$`)
)

func pluginFromID(id string) (typ string, name string, version string) {
matches := pluginIDRegex.FindStringSubmatch(id)
switch {
case matches == nil || len(matches) < 3:
return "", "", ""
case len(matches) == 3:
return matches[1], matches[2], ""
default:
return matches[1], matches[3], matches[2]
}
}

func idFromPlugin(typ, name, version string) string {
if version == "" {
return fmt.Sprintf("%s/name/%s", typ, name)

}

return fmt.Sprintf("%s/version/%s/name/%s", typ, version, name)
}

func pluginResource() *schema.Resource {
return &schema.Resource{
CreateContext: pluginWrite,
Expand Down Expand Up @@ -109,10 +137,7 @@ func pluginWrite(ctx context.Context, d *schema.ResourceData, meta interface{})
}
name := d.Get(consts.FieldName).(string)
version := d.Get(consts.FieldVersion).(string)
id := fmt.Sprintf("%s/%s", pluginType, name)
if version != "" {
id = fmt.Sprintf("%s/%s", id, version)
}
id := idFromPlugin(pluginType.String(), name, version)

if diagErr := versionedPluginsSupported(meta, version); diagErr != nil {
return diagErr
Expand Down Expand Up @@ -152,16 +177,9 @@ func pluginRead(ctx context.Context, d *schema.ResourceData, meta interface{}) d
return diag.FromErr(e)
}

var typ, name, version string
parts := strings.Split(d.Id(), "/")
lenParts := len(parts)
switch lenParts {
case 0, 1:
return diag.Errorf("invalid ID %q, must be of form <type>/<name> or <type>/<name>/<semantic-version>", d.Id())
case 2:
typ, name = parts[0], parts[1]
default:
typ, name, version = parts[0], strings.Join(parts[1:lenParts-1], "/"), parts[lenParts-1]
typ, name, version := pluginFromID(d.Id())
if typ == "" || name == "" {
diag.Errorf("invalid ID %q, must be of form :type/name/:name or :type/version/:version/name/:name", d.Id())
}

if diagErr := versionedPluginsSupported(meta, version); diagErr != nil {
Expand Down
2 changes: 1 addition & 1 deletion vault/resource_plugin_pinned_version_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ resource "vault_plugin_pinned_version" "test" {
name = vault_plugin.test.name
version = vault_plugin.test.version
}
`, testPluginConfig(pluginType, name, version, sha256, os.Getenv(envPluginCommand), `["--arg"]`, `["foo=bar"]`, true))
`, testPluginConfig(pluginType, name, version, sha256, os.Getenv(envPluginCommand), `["--arg"]`, `["foo=bar"]`))

return ret
}
67 changes: 36 additions & 31 deletions vault/resource_plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,39 +39,34 @@ func TestPlugin(t *testing.T) {
sha256Updated := strings.Repeat("12345678", 8)
cmd := os.Getenv(envPluginCommand)

versionsSupported := true
if testProvider != nil {
m := testProvider.Meta().(*provider.ProviderMeta)
versionsSupported = m.GetVaultVersion().GreaterThanOrEqual(provider.VaultVersion112)
}

resource.Test(t, resource.TestCase{
ProviderFactories: providerFactories,
PreCheck: func() {
testutil.TestAccPreCheck(t)
testutil.SkipTestEnvUnset(t, envPluginCommand)
SkipIfAPIVersionLT(t, testProvider.Meta(), provider.VaultVersion112)
},
Steps: []resource.TestStep{
{
Config: testPluginConfig(typ, destName, version, sha256, cmd, args, env, versionsSupported),
Config: testPluginConfig(typ, destName, version, sha256, cmd, args, env),
Check: resource.ComposeTestCheckFunc(

resource.TestCheckResourceAttr(resourceName, consts.FieldType, typ),
resource.TestCheckResourceAttr(resourceName, consts.FieldName, destName),
testCheckVersionAttr(resourceName, version, versionsSupported),
resource.TestCheckResourceAttr(resourceName, consts.FieldVersion, destName),
resource.TestCheckResourceAttr(resourceName, fieldSHA256, sha256),
resource.TestCheckResourceAttr(resourceName, fieldCommand, cmd),
testValidateList(resourceName, fieldArgs, []string{"--foo"}),
testValidateList(resourceName, fieldEnv, []string{"FOO=BAR"}),
),
},
{
Config: testPluginConfig(typ, destName, version, sha256Updated, cmd, argsUpdated, envUpdated, versionsSupported),
Config: testPluginConfig(typ, destName, version, sha256Updated, cmd, argsUpdated, envUpdated),
Check: resource.ComposeTestCheckFunc(

resource.TestCheckResourceAttr(resourceName, consts.FieldType, typ),
resource.TestCheckResourceAttr(resourceName, consts.FieldName, destName),
testCheckVersionAttr(resourceName, version, versionsSupported),
resource.TestCheckResourceAttr(resourceName, consts.FieldVersion, destName),
resource.TestCheckResourceAttr(resourceName, fieldSHA256, sha256Updated),
resource.TestCheckResourceAttr(resourceName, fieldCommand, cmd),
testValidateList(resourceName, fieldArgs, []string{"--bar"}),
Expand All @@ -83,20 +78,7 @@ func TestPlugin(t *testing.T) {
})
}

func testPluginConfig(pluginType, name, version, sha256, command, args, env string, versionsSupported bool) string {
if !versionsSupported {
return fmt.Sprintf(`
resource "vault_plugin" "test" {
type = "%s"
name = "%s"
sha256 = "%s"
command = "%s"
args = %s
env = %s
}
`, pluginType, name, sha256, command, args, env)
}

func testPluginConfig(pluginType, name, version, sha256, command, args, env string) string {
return fmt.Sprintf(`
resource "vault_plugin" "test" {
type = "%s"
Expand Down Expand Up @@ -133,12 +115,35 @@ func testValidateList(resourceName, attr string, expected []string) resource.Tes
}
}

func testCheckVersionAttr(resourceName, expected string, versionsSupported bool) resource.TestCheckFunc {
if versionsSupported {
return resource.TestCheckResourceAttr(resourceName, consts.FieldVersion, expected)
}

return func(*terraform.State) error {
return nil
func TestPluginFromID(t *testing.T) {
for name, tc := range map[string]struct {
id string
typ string
name string
version string
}{
"auth": {"auth/version/v1.0.0/name/foo", "auth", "foo", "v1.0.0"},
"secret": {"secret/version/v1.0.0/name/foo", "secret", "foo", "v1.0.0"},
"database": {"database/version/v1.0.0/name/foo", "database", "foo", "v1.0.0"},
"no version": {"auth/name/foo", "auth", "foo", ""},
"weird version": {"auth/version/bad-semver/name/foo", "auth", "foo", "bad-semver"},
"name with slashes": {"auth/version/v1.0.0/name/foo/bar/baz", "auth", "foo/bar/baz", "v1.0.0"},
"no version and name with slashes": {"auth/name/foo/bar/baz", "auth", "foo/bar/baz", ""},
"missing type": {"version/v1.0.0/name/foo", "", "", ""},
"invalid type": {"new-type/version/v1.0.0/name/foo", "", "", ""},
"missing name": {"auth/version/v1.0.0", "", "", ""},
} {
t.Run(name, func(t *testing.T) {
typ, name, version := pluginFromID(tc.id)
if typ != tc.typ {
t.Errorf("expected type %q, got %q", tc.typ, typ)
}
if name != tc.name {
t.Errorf("expected name %q, got %q", tc.name, name)
}
if version != tc.version {
t.Errorf("expected version %q, got %q", tc.version, version)
}
})
}
}

0 comments on commit 77f35a4

Please sign in to comment.