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

Support configuring vault version handling. #1646

Merged
merged 4 commits into from
Oct 26, 2022
Merged
Show file tree
Hide file tree
Changes from 3 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
2 changes: 2 additions & 0 deletions internal/consts/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ const (
FieldClientToken = "client_token"
FieldWrappedToken = "wrapped_token"
FieldOrphan = "orphan"
FieldVaultVersionOverride = "vault_version_override"
FieldSkipGetVaultVersion = "skip_get_vault_version"

/*
common environment variables
Expand Down
28 changes: 21 additions & 7 deletions internal/provider/meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,11 @@ func (p *ProviderMeta) GetNSClient(ns string) (*api.Client, error) {
// ProviderMeta vaultVersion is above the
// minimum version.
func (p *ProviderMeta) IsAPISupported(minVersion *version.Version) bool {
return p.vaultVersion.GreaterThanOrEqual(minVersion)
ver := p.GetVaultVersion()
if ver == nil {
return false
}
return ver.GreaterThanOrEqual(minVersion)
}

// GetVaultVersion returns the providerMeta
Expand Down Expand Up @@ -234,12 +238,22 @@ func NewProviderMeta(d *schema.ResourceData) (interface{}, error) {
}
}

// Set the Vault version to *ProviderMeta object
vaultVersion, err := getVaultVersion(client)
if err != nil {
return nil, err
var vaultVersion *version.Version
if v, ok := d.GetOk(consts.FieldVaultVersionOverride); ok {
ver, err := version.NewVersion(v.(string))
if err != nil {
return nil, fmt.Errorf("invalid value for %q, err=%w",
consts.FieldVaultVersionOverride, err)
}
vaultVersion = ver
} else if !d.Get(consts.FieldSkipGetVaultVersion).(bool) {
// Set the Vault version to *ProviderMeta object
ver, err := getVaultVersion(client)
if err != nil {
return nil, err
}
vaultVersion = ver
}

// Set the namespace to the requested namespace, if provided
namespace := d.Get(consts.FieldNamespace).(string)
if namespace != "" {
Expand Down Expand Up @@ -331,7 +345,7 @@ func IsAPISupported(meta interface{}, minVersion *version.Version) bool {
func getVaultVersion(client *api.Client) (*version.Version, error) {
resp, err := client.Sys().SealStatus()
if err != nil {
return nil, err
return nil, fmt.Errorf("could not determine the Vault server version, err=%s", err)
}

if resp == nil {
Expand Down
30 changes: 17 additions & 13 deletions internal/provider/meta_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,37 +378,46 @@ func TestIsAPISupported(t *testing.T) {

testCases := []struct {
name string
minVersion string
minVersion *version.Version
expected bool
meta interface{}
}{
{
name: "server-greater-than",
minVersion: "1.8.0",
name: "supported-greater-than",
minVersion: version.Must(version.NewSemver("1.8.0")),
expected: true,
meta: &ProviderMeta{
client: rootClient,
vaultVersion: VaultVersion11,
},
},
{
name: "server-less-than",
minVersion: "1.12.0",
name: "supported-less-than",
minVersion: version.Must(version.NewSemver("1.12.0")),
expected: false,
meta: &ProviderMeta{
client: rootClient,
vaultVersion: VaultVersion11,
},
},
{
name: "server-equal",
minVersion: "1.10.0",
name: "supported-equal",
minVersion: version.Must(version.NewSemver("1.10.0")),
expected: true,
meta: &ProviderMeta{
client: rootClient,
vaultVersion: VaultVersion10,
},
},
{
name: "unsupported-unset",
minVersion: version.Must(version.NewSemver("1.12.0")),
expected: false,
meta: &ProviderMeta{
client: rootClient,
vaultVersion: nil,
},
},
}

for _, tt := range testCases {
Expand All @@ -427,12 +436,7 @@ func TestIsAPISupported(t *testing.T) {
tt.meta = m
}

mv, err := version.NewVersion(tt.minVersion)
if err != nil {
t.Fatal(err)
}

isTFVersionGreater := tt.meta.(*ProviderMeta).IsAPISupported(mv)
isTFVersionGreater := tt.meta.(*ProviderMeta).IsAPISupported(tt.minVersion)

if isTFVersionGreater != tt.expected {
t.Errorf("IsAPISupported() got = %v, want %v", isTFVersionGreater, tt.expected)
Expand Down
19 changes: 19 additions & 0 deletions internal/provider/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/gosimple/slug"
"github.com/hashicorp/go-cty/cty"
"github.com/hashicorp/go-version"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

Expand Down Expand Up @@ -188,3 +189,21 @@ func ValidateDiagUUID(i interface{}, path cty.Path) diag.Diagnostics {

return nil
}

// ValidateSemVer validates that the input string conforms to SemVer 2.0.0
func ValidateDiagSemVer(i interface{}, path cty.Path) diag.Diagnostics {
have := i.(string)
if _, err := version.NewSemver(have); err != nil {
return diag.Diagnostics{
{
Severity: diag.Error,
Summary: "Invalid semantic version",
Detail: "Value must be in valid semantic version string, e.g. " +
"1.12.0",
AttributePath: path,
},
}
}

return nil
}
51 changes: 51 additions & 0 deletions internal/provider/validators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -371,3 +371,54 @@ func TestValidateDiagUUID(t *testing.T) {
})
}
}

func TestValidateDiagSemVer(t *testing.T) {
want := diag.Diagnostics{
{
Severity: diag.Error,
Summary: "Invalid semantic version",
Detail: "Value must be in valid semantic version string, e.g. " +
"1.12.0",
AttributePath: nil,
},
}
type args struct{}
tests := []struct {
name string
i interface{}
path cty.Path
want diag.Diagnostics
}{
{
name: "invalid",
i: "v0. 2.0",
path: nil,
want: want,
},
{
name: "invalid-empty",
i: "",
path: nil,
want: want,
},
{
name: "valid",
i: "0.2.0",
path: nil,
want: nil,
},
{
name: "valid-with-v-prefix",
i: "v0.2.0",
path: nil,
want: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ValidateDiagSemVer(tt.i, tt.path); !reflect.DeepEqual(got, tt.want) {
t.Errorf("ValidateDiagSemVer() = %v, want %v", got, tt.want)
}
})
}
}
14 changes: 14 additions & 0 deletions vault/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,20 @@ func Provider() *schema.Provider {
},
},
},
consts.FieldSkipGetVaultVersion: {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "Skip the dynamic fetching of the Vault server version.",
ValidateDiagFunc: provider.ValidateDiagSemVer,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be validating a semantic version since this is a boolean?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, good catch! Fixed with 8e28053

},
consts.FieldVaultVersionOverride: {
Type: schema.TypeString,
Optional: true,
Description: "Override the Vault server version, " +
"which is normally determined dynamically from the target Vault server",
ValidateDiagFunc: provider.ValidateDiagSemVer,
},
},
ConfigureFunc: provider.NewProviderMeta,
DataSourcesMap: dataSourcesMap,
Expand Down
13 changes: 13 additions & 0 deletions website/docs/index.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,18 @@ variables in order to keep credential information out of the configuration.
See [namespaces](https://www.vaultproject.io/docs/enterprise/namespaces) for more info.
*Available only for Vault Enterprise*.

* `skip_get_vault_version` - (Optional) Skip the dynamic fetching of the Vault server version.
Set to `true` when the */sys/seal-status* API endpoint is not available. See [vault_version_override](#vault_version_override)
for related info

* `vault_version_override` - (Optional) Override the target Vault server semantic version.
Normally the version is dynamically set from the */sys/seal-status* API endpoint. In the case where this endpoint
is not available an override can be specified here.

~> Setting the `vault_version_override` determines Vault server's API compatability, so
it's important that the value specified here matches the target server. It is recommended to
only ever use this option in the case where the server version cannot be dynamically determined.

* `headers` - (Optional) A configuration block, described below, that provides headers
to be sent along with all requests to the Vault server. This block can be specified
multiple times.
Expand All @@ -221,6 +233,7 @@ The `headers` configuration block accepts the following arguments:

* `value` - (Required) The value of the header.


## Vault Authentication Configuration Options

The Vault provider supports the following Vault authentication engines.
Expand Down