From 0e3e721509a69e36a159666cd21dce250d148ac7 Mon Sep 17 00:00:00 2001 From: HamzaShili65 Date: Wed, 23 Jul 2025 18:41:21 -0700 Subject: [PATCH 1/8] add config types for reporting, user_lockout, and experiments --- internal/plugin/vault_config_experiments.go | 72 +++++++++ internal/plugin/vault_config_reporting.go | 162 +++++++++++++++++++ internal/plugin/vault_config_user_lockout.go | 102 ++++++++++++ 3 files changed, 336 insertions(+) create mode 100644 internal/plugin/vault_config_experiments.go create mode 100644 internal/plugin/vault_config_reporting.go create mode 100644 internal/plugin/vault_config_user_lockout.go diff --git a/internal/plugin/vault_config_experiments.go b/internal/plugin/vault_config_experiments.go new file mode 100644 index 0000000..7aa8216 --- /dev/null +++ b/internal/plugin/vault_config_experiments.go @@ -0,0 +1,72 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package plugin + +import ( + "fmt" + "github.com/hashicorp/terraform-plugin-go/tftypes" +) + +type vaultExperimentsConfig struct { + Experiments []*tfString + RawValues map[string]tftypes.Value + RawValue tftypes.Value + Unknown bool + Null bool +} + +func newVaultExperimentsConfig() *vaultExperimentsConfig { + return &vaultExperimentsConfig{ + Experiments: []*tfString{}, + Unknown: false, + Null: true, + } +} + +func (s *vaultExperimentsConfig) FromTerraform5Value(val tftypes.Value) error { + if s == nil { + return fmt.Errorf("cannot unmarshal %s into nil vaultExperimentsConfig", val.String()) + } + if val.IsNull() { + s.Null = true + s.Unknown = false + return nil + } + if !val.IsKnown() { + s.Unknown = true + return nil + } + var experiments []string + err := val.As(&experiments) + if err != nil { + return err + } + s.Experiments = []*tfString{} + for _, exp := range experiments { + ts := newTfString() + ts.Set(exp) + s.Experiments = append(s.Experiments, ts) + } + return nil +} + +func (s *vaultExperimentsConfig) Terraform5Type() tftypes.Type { + return tftypes.List{ElementType: tftypes.String} +} + +func (s *vaultExperimentsConfig) Terraform5Value() tftypes.Value { + if s.Null { + return tftypes.NewValue(s.Terraform5Type(), nil) + } + if s.Unknown { + return tftypes.NewValue(s.Terraform5Type(), tftypes.UnknownValue) + } + exps := []string{} + for _, ts := range s.Experiments { + if val, ok := ts.Get(); ok { + exps = append(exps, val) + } + } + return tftypes.NewValue(s.Terraform5Type(), exps) +} diff --git a/internal/plugin/vault_config_reporting.go b/internal/plugin/vault_config_reporting.go new file mode 100644 index 0000000..c9847c8 --- /dev/null +++ b/internal/plugin/vault_config_reporting.go @@ -0,0 +1,162 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package plugin + +import ( + "fmt" + "github.com/hashicorp/terraform-plugin-go/tftypes" +) + +type vaultReportingLicenseConfig struct { + Enabled *tfBool + BillingStartTimestamp *tfString + DevelopmentCluster *tfBool +} + +func newVaultReportingLicenseConfig() *vaultReportingLicenseConfig { + return &vaultReportingLicenseConfig{ + Enabled: newTfBool(), + BillingStartTimestamp: newTfString(), + DevelopmentCluster: newTfBool(), + } +} + +type vaultReportingConfig struct { + SnapshotRetentionTime *tfString + DisableProductUsageReporting *tfBool + License *vaultReportingLicenseConfig + Unknown bool + Null bool +} + +func newVaultReportingConfig() *vaultReportingConfig { + return &vaultReportingConfig{ + SnapshotRetentionTime: newTfString(), + DisableProductUsageReporting: newTfBool(), + License: newVaultReportingLicenseConfig(), + Unknown: false, + Null: true, + } +} + +func (s *vaultReportingConfig) FromTerraform5Value(val tftypes.Value) error { + if s == nil { + return fmt.Errorf("cannot unmarshal %s into nil vaultReportingConfig", val.String()) + } + if val.IsNull() { + s.Null = true + s.Unknown = false + return nil + } + if !val.IsKnown() { + s.Unknown = true + return nil + } + vals := map[string]tftypes.Value{} + err := val.As(&vals) + if err != nil { + return err + } + for k, v := range vals { + switch k { + case "snapshot_retention_time": + err = s.SnapshotRetentionTime.FromTFValue(v) + case "disable_product_usage_reporting": + err = s.DisableProductUsageReporting.FromTFValue(v) + case "license": + err = s.License.FromTerraform5Value(v) + default: + return fmt.Errorf("unknown reporting config key: %s", k) + } + if err != nil { + return err + } + } + return nil +} + +func (s *vaultReportingConfig) Terraform5Type() tftypes.Type { + return tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "snapshot_retention_time": tftypes.String, + "disable_product_usage_reporting": tftypes.Bool, + "license": newVaultReportingLicenseConfig().Terraform5Type(), + }, + OptionalAttributes: map[string]struct{}{ + "snapshot_retention_time": {}, + "disable_product_usage_reporting": {}, + "license": {}, + }, + } +} + +func (s *vaultReportingConfig) Terraform5Value() tftypes.Value { + if s.Null { + return tftypes.NewValue(s.Terraform5Type(), nil) + } + if s.Unknown { + return tftypes.NewValue(s.Terraform5Type(), tftypes.UnknownValue) + } + return tftypes.NewValue(s.Terraform5Type(), map[string]tftypes.Value{ + "snapshot_retention_time": s.SnapshotRetentionTime.TFValue(), + "disable_product_usage_reporting": s.DisableProductUsageReporting.TFValue(), + "license": s.License.Terraform5Value(), + }) +} + +func (s *vaultReportingLicenseConfig) FromTerraform5Value(val tftypes.Value) error { + if s == nil { + return fmt.Errorf("cannot unmarshal %s into nil vaultReportingLicenseConfig", val.String()) + } + if val.IsNull() { + return nil + } + if !val.IsKnown() { + return nil + } + vals := map[string]tftypes.Value{} + err := val.As(&vals) + if err != nil { + return err + } + for k, v := range vals { + switch k { + case "enabled": + err = s.Enabled.FromTFValue(v) + case "billing_start_timestamp": + err = s.BillingStartTimestamp.FromTFValue(v) + case "development_cluster": + err = s.DevelopmentCluster.FromTFValue(v) + default: + return fmt.Errorf("unknown license config key: %s", k) + } + if err != nil { + return err + } + } + return nil +} + +func (s *vaultReportingLicenseConfig) Terraform5Type() tftypes.Type { + return tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "enabled": tftypes.Bool, + "billing_start_timestamp": tftypes.String, + "development_cluster": tftypes.Bool, + }, + OptionalAttributes: map[string]struct{}{ + "enabled": {}, + "billing_start_timestamp": {}, + "development_cluster": {}, + }, + } +} + +func (s *vaultReportingLicenseConfig) Terraform5Value() tftypes.Value { + return tftypes.NewValue(s.Terraform5Type(), map[string]tftypes.Value{ + "enabled": s.Enabled.TFValue(), + "billing_start_timestamp": s.BillingStartTimestamp.TFValue(), + "development_cluster": s.DevelopmentCluster.TFValue(), + }) +} diff --git a/internal/plugin/vault_config_user_lockout.go b/internal/plugin/vault_config_user_lockout.go new file mode 100644 index 0000000..ffcb129 --- /dev/null +++ b/internal/plugin/vault_config_user_lockout.go @@ -0,0 +1,102 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package plugin + +import ( + "fmt" + "github.com/hashicorp/terraform-plugin-go/tftypes" +) + +type vaultUserLockoutConfig struct { + LockoutThreshold *tfString + LockoutDuration *tfString + LockoutCounterReset *tfString + DisableLockout *tfBool + + RawValues map[string]tftypes.Value + RawValue tftypes.Value + Unknown bool + Null bool +} + +func newVaultUserLockoutConfig() *vaultUserLockoutConfig { + return &vaultUserLockoutConfig{ + LockoutThreshold: newTfString(), + LockoutDuration: newTfString(), + LockoutCounterReset: newTfString(), + DisableLockout: newTfBool(), + Unknown: false, + Null: true, + } +} + +func (s *vaultUserLockoutConfig) FromTerraform5Value(val tftypes.Value) error { + if s == nil { + return fmt.Errorf("cannot unmarshal %s into nil vaultUserLockoutConfig", val.String()) + } + if val.IsNull() { + s.Null = true + s.Unknown = false + return nil + } + if !val.IsKnown() { + s.Unknown = true + return nil + } + vals := map[string]tftypes.Value{} + err := val.As(&vals) + if err != nil { + return err + } + for k, v := range vals { + switch k { + case "lockout_threshold": + err = s.LockoutThreshold.FromTFValue(v) + case "lockout_duration": + err = s.LockoutDuration.FromTFValue(v) + case "lockout_counter_reset": + err = s.LockoutCounterReset.FromTFValue(v) + case "disable_lockout": + err = s.DisableLockout.FromTFValue(v) + default: + return fmt.Errorf("unknown user_lockout config key: %s", k) + } + if err != nil { + return err + } + } + return nil +} + +func (s *vaultUserLockoutConfig) Terraform5Type() tftypes.Type { + return tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "lockout_threshold": tftypes.String, + "lockout_duration": tftypes.String, + "lockout_counter_reset": tftypes.String, + "disable_lockout": tftypes.Bool, + }, + OptionalAttributes: map[string]struct{}{ + "lockout_threshold": {}, + "lockout_duration": {}, + "lockout_counter_reset": {}, + "disable_lockout": {}, + }, + } +} + +func (s *vaultUserLockoutConfig) Terraform5Value() tftypes.Value { + if s.Null { + return tftypes.NewValue(s.Terraform5Type(), nil) + } + if s.Unknown { + return tftypes.NewValue(s.Terraform5Type(), tftypes.UnknownValue) + } + return tftypes.NewValue(s.Terraform5Type(), map[string]tftypes.Value{ + "lockout_threshold": s.LockoutThreshold.TFValue(), + "lockout_duration": s.LockoutDuration.TFValue(), + "lockout_counter_reset": s.LockoutCounterReset.TFValue(), + "disable_lockout": s.DisableLockout.TFValue(), + }) +} From e8e3f99261171959d726de10ded2ad204d1d3099 Mon Sep 17 00:00:00 2001 From: HamzaShili65 Date: Wed, 23 Jul 2025 18:41:57 -0700 Subject: [PATCH 2/8] add support for remaining vault configs --- internal/plugin/resource_vault_start.go | 458 +++++++++++++++++++++++- 1 file changed, 446 insertions(+), 12 deletions(-) diff --git a/internal/plugin/resource_vault_start.go b/internal/plugin/resource_vault_start.go index f1a778d..666514f 100644 --- a/internal/plugin/resource_vault_start.go +++ b/internal/plugin/resource_vault_start.go @@ -73,6 +73,36 @@ type vaultConfig struct { Seals *vaultSealsConfig // HA Seal configuration Telemetry *dynamicPseudoTypeBlock UI *tfBool + + // Added fields from Vault config docs + HAStorage *vaultStorageConfig + UserLockout *vaultUserLockoutConfig + Reporting *vaultReportingConfig + CacheSize *tfNum + DisableCache *tfBool + DisableMlock *tfBool + PluginDirectory *tfString + PluginTmpdir *tfString + PluginFileUID *tfNum + PluginFilePermissions *tfNum + DefaultLeaseTTL *tfString + MaxLeaseTTL *tfString + DefaultMaxRequestDuration *tfString + DetectDeadlocks *tfBool + RawStorageEndpoint *tfString + IntrospectionEndpoint *tfString + PidFile *tfString + EnableResponseHeaderHostname *tfBool + EnableResponseHeaderRaftNodeID *tfBool + LogFormat *tfString + LogFile *tfString + LogRotateDuration *tfString + LogRotateBytes *tfNum + LogRotateMaxFiles *tfNum + Experiments *vaultExperimentsConfig + ImpreciseLeaseRoleTracking *tfBool + EnablePostUnsealTrace *tfBool + PostUnsealTraceDirectory *tfString } var _ state.State = (*vaultStartStateV1)(nil) @@ -120,6 +150,35 @@ func newVaultConfig() *vaultConfig { Storage: newVaultStorageConfig(), Telemetry: newDynamicPseudoTypeBlock(), UI: newTfBool(), + + HAStorage: newVaultStorageConfig(), + UserLockout: newVaultUserLockoutConfig(), + Reporting: newVaultReportingConfig(), + CacheSize: newTfNum(), + DisableCache: newTfBool(), + DisableMlock: newTfBool(), + PluginDirectory: newTfString(), + PluginTmpdir: newTfString(), + PluginFileUID: newTfNum(), + PluginFilePermissions: newTfNum(), + DefaultLeaseTTL: newTfString(), + MaxLeaseTTL: newTfString(), + DefaultMaxRequestDuration: newTfString(), + DetectDeadlocks: newTfBool(), + RawStorageEndpoint: newTfString(), + IntrospectionEndpoint: newTfString(), + PidFile: newTfString(), + EnableResponseHeaderHostname: newTfBool(), + EnableResponseHeaderRaftNodeID: newTfBool(), + LogFormat: newTfString(), + LogFile: newTfString(), + LogRotateDuration: newTfString(), + LogRotateBytes: newTfNum(), + LogRotateMaxFiles: newTfNum(), + Experiments: newVaultExperimentsConfig(), + ImpreciseLeaseRoleTracking: newTfBool(), + EnablePostUnsealTrace: newTfBool(), + PostUnsealTraceDirectory: newTfString(), } } @@ -325,6 +384,34 @@ As such, you will need to provide _all_ values except for ^seals^ until we make - ^config.seals.tertiary.type^ (String) The Vault [seal](https://developer.hashicorp.com/vault/docs/configuration/seal) type - ^config.seals.tertiary.attributes^ (String) The Vault [seal](https://developer.hashicorp.com/vault/docs/configuration/seal) parameters for the given seal type - ^config.telemetry^ (Object) The Vault [telemetry](https://developer.hashicorp.com/vault/docs/configuration/telemetry#telemetry-parameters) stanza +- ^config.ha_storage^ (Object) The Vault [ha_storage](https://developer.hashicorp.com/vault/docs/internals/high-availability?productSlug=vault&tutorialSlug=raft&tutorialSlug=raft-ha-storage) stanza +- ^config.user_lockout^ (Object) The Vault [user_lockout](https://developer.hashicorp.com/vault/docs/configuration/user-lockout) stanza +- ^config.reporting^ (Object) The Vault [reporting](https://developer.hashicorp.com/vault/docs/configuration/reporting) stanza +- ^config.cache_size^ (Number) The Vault [cache_size](https://developer.hashicorp.com/vault/docs/configuration#cache_size) value +- ^config.disable_cache^ (Bool) The Vault [disable_cache](https://developer.hashicorp.com/vault/docs/configuration#disable_cache) value +- ^config.disable_mlock^ (Bool) The Vault [disable_mlock](https://developer.hashicorp.com/vault/docs/configuration#disable_mlock) value +- ^config.plugin_directory^ (String) The Vault [plugin_directory](https://developer.hashicorp.com/vault/docs/configuration#plugin_directory) value +- ^config.plugin_tmpdir^ (String) The Vault [plugin_tmpdir](https://developer.hashicorp.com/vault/docs/configuration#plugin_tmpdir) value +- ^config.plugin_file_uid^ (Number) The Vault [plugin_file_uid](https://developer.hashicorp.com/vault/docs/configuration#plugin_file_uid) value +- ^config.plugin_file_permissions^ (Number) The Vault [plugin_file_permissions](https://developer.hashicorp.com/vault/docs/configuration#plugin_file_permissions) value +- ^config.default_lease_ttl^ (String) The Vault [default_lease_ttl](https://developer.hashicorp.com/vault/docs/configuration#default_lease_ttl) value +- ^config.max_lease_ttl^ (String) The Vault [max_lease_ttl](https://developer.hashicorp.com/vault/docs/configuration#max_lease_ttl) value +- ^config.default_max_request_duration^ (String) The Vault [default_max_request_duration](https://developer.hashicorp.com/vault/docs/configuration#default_max_request_duration) value +- ^config.detect_deadlocks^ (Bool) The Vault [detect_deadlocks](https://developer.hashicorp.com/vault/docs/configuration#detect_deadlocks) value +- ^config.raw_storage_endpoint^ (String) The Vault [raw_storage_endpoint](https://developer.hashicorp.com/vault/docs/configuration#raw_storage_endpoint) value +- ^config.introspection_endpoint^ (String) The Vault [introspection_endpoint](https://developer.hashicorp.com/vault/docs/configuration#introspection_endpoint) value +- ^config.pid_file^ (String) The Vault [pid_file](https://developer.hashicorp.com/vault/docs/configuration#pid_file) value +- ^config.enable_response_header_hostname^ (Bool) The Vault [enable_response_header_hostname](https://developer.hashicorp.com/vault/docs/configuration#enable_response_header_hostname) value +- ^config.enable_response_header_raft_node_id^ (Bool) The Vault [enable_response_header_raft_node_id](https://developer.hashicorp.com/vault/docs/configuration#enable_response_header_raft_node_id) value +- ^config.log_format^ (String) The Vault [log_format](https://developer.hashicorp.com/vault/docs/configuration#log_format) value +- ^config.log_file^ (String) The Vault [log_file](https://developer.hashicorp.com/vault/docs/configuration#log_file) value +- ^config.log_rotate_duration^ (String) The Vault [log_rotate_duration](https://developer.hashicorp.com/vault/docs/configuration#log_rotate_duration) value +- ^config.log_rotate_bytes^ (Number) The Vault [log_rotate_bytes](https://developer.hashicorp.com/vault/docs/configuration#log_rotate_bytes) value +- ^config.log_rotate_max_files^ (Number) The Vault [log_rotate_max_files](https://developer.hashicorp.com/vault/docs/configuration#log_rotate_max_files) value +- ^config.experiments^ (Object) The Vault [experiments](https://developer.hashicorp.com/vault/docs/configuration#experiments) stanza +- ^config.imprecise_lease_role_tracking^ (Bool) The Vault [imprecise_lease_role_tracking](https://developer.hashicorp.com/vault/docs/configuration#imprecise_lease_role_tracking) value +- ^config.enable_post_unseal_trace^ (Bool) The Vault [enable_post_unseal_trace](https://developer.hashicorp.com/vault/docs/configuration#enable_post_unseal_trace) value +- ^config.post_unseal_trace_directory^ (String) The Vault [post_unseal_trace_directory](https://developer.hashicorp.com/vault/docs/configuration#post_unseal_trace_directory) value `), }, { @@ -506,29 +593,83 @@ func (c *vaultConfig) attrs() map[string]tftypes.Type { "seals": c.Seals.Terraform5Type(), "telemetry": c.Telemetry.TFType(), "ui": c.UI.TFType(), + + "ha_storage": c.HAStorage.Terraform5Type(), + "user_lockout": c.UserLockout.Terraform5Type(), + "reporting": c.Reporting.Terraform5Type(), + "cache_size": tftypes.Number, + "disable_cache": tftypes.Bool, + "disable_mlock": tftypes.Bool, + "plugin_directory": tftypes.String, + "plugin_tmpdir": tftypes.String, + "plugin_file_uid": tftypes.Number, + "plugin_file_permissions": tftypes.Number, + "default_lease_ttl": tftypes.String, + "max_lease_ttl": tftypes.String, + "default_max_request_duration": tftypes.String, + "detect_deadlocks": tftypes.Bool, + "raw_storage_endpoint": tftypes.String, + "introspection_endpoint": tftypes.String, + "pid_file": tftypes.String, + "enable_response_header_hostname": tftypes.Bool, + "enable_response_header_raft_node_id": tftypes.Bool, + "log_format": tftypes.String, + "log_file": tftypes.String, + "log_rotate_duration": tftypes.String, + "log_rotate_bytes": tftypes.Number, + "log_rotate_max_files": tftypes.Number, + "experiments": c.Experiments.Terraform5Type(), + "imprecise_lease_role_tracking": tftypes.Bool, + "enable_post_unseal_trace": tftypes.Bool, + "post_unseal_trace_directory": tftypes.String, } } func (c *vaultConfig) optionalAttrs() map[string]struct{} { return map[string]struct{}{ - "seal": {}, - "seals": {}, - "storage": {}, - "telemetry": {}, + "seal": {}, + "seals": {}, + "storage": {}, + "telemetry": {}, + "ha_storage": {}, + "user_lockout": {}, + "reporting": {}, + "cache_size": {}, + "disable_cache": {}, + "disable_mlock": {}, + "plugin_directory": {}, + "plugin_tmpdir": {}, + "plugin_file_uid": {}, + "plugin_file_permissions": {}, + "default_lease_ttl": {}, + "max_lease_ttl": {}, + "default_max_request_duration": {}, + "detect_deadlocks": {}, + "raw_storage_endpoint": {}, + "introspection_endpoint": {}, + "pid_file": {}, + "enable_response_header_hostname": {}, + "enable_response_header_raft_node_id": {}, + "log_format": {}, + "log_file": {}, + "log_rotate_duration": {}, + "log_rotate_bytes": {}, + "log_rotate_max_files": {}, + "experiments": {}, + "imprecise_lease_role_tracking": {}, + "enable_post_unseal_trace": {}, + "post_unseal_trace_directory": {}, } } func (c *vaultConfig) Terraform5Value() tftypes.Value { - typ := tftypes.Object{ - AttributeTypes: c.attrs(), - } - telemetry, err := c.Telemetry.TFValue() if err != nil { panic(err) } - - return tftypes.NewValue(typ, map[string]tftypes.Value{ + return tftypes.NewValue(tftypes.Object{ + AttributeTypes: c.attrs(), + }, map[string]tftypes.Value{ "cluster_name": c.ClusterName.TFValue(), "api_addr": c.APIAddr.TFValue(), "cluster_addr": c.ClusterAddr.TFValue(), @@ -539,10 +680,38 @@ func (c *vaultConfig) Terraform5Value() tftypes.Value { "storage": c.Storage.Terraform5Value(), "telemetry": telemetry, "ui": c.UI.TFValue(), + + "ha_storage": c.HAStorage.Terraform5Value(), + "user_lockout": c.UserLockout.Terraform5Value(), + "reporting": c.Reporting.Terraform5Value(), + "cache_size": c.CacheSize.TFValue(), + "disable_cache": c.DisableCache.TFValue(), + "disable_mlock": c.DisableMlock.TFValue(), + "plugin_directory": c.PluginDirectory.TFValue(), + "plugin_tmpdir": c.PluginTmpdir.TFValue(), + "plugin_file_uid": c.PluginFileUID.TFValue(), + "plugin_file_permissions": c.PluginFilePermissions.TFValue(), + "default_lease_ttl": c.DefaultLeaseTTL.TFValue(), + "max_lease_ttl": c.MaxLeaseTTL.TFValue(), + "default_max_request_duration": c.DefaultMaxRequestDuration.TFValue(), + "detect_deadlocks": c.DetectDeadlocks.TFValue(), + "raw_storage_endpoint": c.RawStorageEndpoint.TFValue(), + "introspection_endpoint": c.IntrospectionEndpoint.TFValue(), + "pid_file": c.PidFile.TFValue(), + "enable_response_header_hostname": c.EnableResponseHeaderHostname.TFValue(), + "enable_response_header_raft_node_id": c.EnableResponseHeaderRaftNodeID.TFValue(), + "log_format": c.LogFormat.TFValue(), + "log_file": c.LogFile.TFValue(), + "log_rotate_duration": c.LogRotateDuration.TFValue(), + "log_rotate_bytes": c.LogRotateBytes.TFValue(), + "log_rotate_max_files": c.LogRotateMaxFiles.TFValue(), + "experiments": c.Experiments.Terraform5Value(), + "imprecise_lease_role_tracking": c.ImpreciseLeaseRoleTracking.TFValue(), + "enable_post_unseal_trace": c.EnablePostUnsealTrace.TFValue(), + "post_unseal_trace_directory": c.PostUnsealTraceDirectory.TFValue(), }) } -// FromTerraform5Value unmarshals the value to the struct. func (c *vaultConfig) FromTerraform5Value(val tftypes.Value) error { vals, err := mapAttributesTo(val, map[string]any{ "api_addr": c.APIAddr, @@ -550,6 +719,31 @@ func (c *vaultConfig) FromTerraform5Value(val tftypes.Value) error { "cluster_name": c.ClusterName, "log_level": c.LogLevel, "ui": c.UI, + + "cache_size": c.CacheSize, + "disable_cache": c.DisableCache, + "disable_mlock": c.DisableMlock, + "plugin_directory": c.PluginDirectory, + "plugin_tmpdir": c.PluginTmpdir, + "plugin_file_uid": c.PluginFileUID, + "plugin_file_permissions": c.PluginFilePermissions, + "default_lease_ttl": c.DefaultLeaseTTL, + "max_lease_ttl": c.MaxLeaseTTL, + "default_max_request_duration": c.DefaultMaxRequestDuration, + "detect_deadlocks": c.DetectDeadlocks, + "raw_storage_endpoint": c.RawStorageEndpoint, + "introspection_endpoint": c.IntrospectionEndpoint, + "pid_file": c.PidFile, + "enable_response_header_hostname": c.EnableResponseHeaderHostname, + "enable_response_header_raft_node_id": c.EnableResponseHeaderRaftNodeID, + "log_format": c.LogFormat, + "log_file": c.LogFile, + "log_rotate_duration": c.LogRotateDuration, + "log_rotate_bytes": c.LogRotateBytes, + "log_rotate_max_files": c.LogRotateMaxFiles, + "imprecise_lease_role_tracking": c.ImpreciseLeaseRoleTracking, + "enable_post_unseal_trace": c.EnablePostUnsealTrace, + "post_unseal_trace_directory": c.PostUnsealTraceDirectory, }) if err != nil { return err @@ -595,6 +789,36 @@ func (c *vaultConfig) FromTerraform5Value(val tftypes.Value) error { } } + // New fields + haStorage, ok := vals["ha_storage"] + if ok { + err = c.HAStorage.FromTerraform5Value(haStorage) + if err != nil { + return err + } + } + userLockout, ok := vals["user_lockout"] + if ok { + err = c.UserLockout.FromTerraform5Value(userLockout) + if err != nil { + return err + } + } + reporting, ok := vals["reporting"] + if ok { + err = c.Reporting.FromTerraform5Value(reporting) + if err != nil { + return err + } + } + experiments, ok := vals["experiments"] + if ok { + err = c.Experiments.FromTerraform5Value(experiments) + if err != nil { + return err + } + } + return nil } @@ -767,6 +991,216 @@ func (c *vaultConfig) Render(configMode string) (*hcl.Builder, map[string]string hclBuilder.AppendBlock("telemetry", nil).AppendAttributes(telemetry) } + // HAStorage + if c.HAStorage != nil && c.HAStorage.Type != nil { + if haStorageLabel, ok := c.HAStorage.Type.Get(); ok { + haStorageBlock := hclBuilder.AppendBlock("ha_storage", []string{haStorageLabel}) + if haAttrs, ok := c.HAStorage.Attrs.Object.GetObject(); ok { + haStorageBlock.AppendAttributes(haAttrs) + } + } + } + + // UserLockout + if c.UserLockout != nil { + userLockoutBlock := hclBuilder.AppendBlock("user_lockout", nil) + if val, ok := c.UserLockout.LockoutThreshold.Get(); ok { + userLockoutBlock.AppendAttribute("lockout_threshold", val) + } + if val, ok := c.UserLockout.LockoutDuration.Get(); ok { + userLockoutBlock.AppendAttribute("lockout_duration", val) + } + if val, ok := c.UserLockout.LockoutCounterReset.Get(); ok { + userLockoutBlock.AppendAttribute("lockout_counter_reset", val) + } + if val, ok := c.UserLockout.DisableLockout.Get(); ok { + userLockoutBlock.AppendAttribute("disable_lockout", val) + } + } + + // Reporting + if c.Reporting != nil { + reportingBlock := hclBuilder.AppendBlock("reporting", nil) + if val, ok := c.Reporting.SnapshotRetentionTime.Get(); ok { + reportingBlock.AppendAttribute("snapshot_retention_time", val) + } + if val, ok := c.Reporting.DisableProductUsageReporting.Get(); ok { + reportingBlock.AppendAttribute("disable_product_usage_reporting", val) + } + if c.Reporting.License != nil { + licenseBlock := reportingBlock.AppendBlock("license", nil) + if val, ok := c.Reporting.License.Enabled.Get(); ok { + licenseBlock.AppendAttribute("enabled", val) + } + if val, ok := c.Reporting.License.BillingStartTimestamp.Get(); ok { + licenseBlock.AppendAttribute("billing_start_timestamp", val) + } + if val, ok := c.Reporting.License.DevelopmentCluster.Get(); ok { + licenseBlock.AppendAttribute("development_cluster", val) + } + } + } + + // Experiments + if c.Experiments != nil && len(c.Experiments.Experiments) > 0 { + exps := []string{} + for _, ts := range c.Experiments.Experiments { + if val, ok := ts.Get(); ok { + exps = append(exps, val) + } + } + if configMode == "file" { + hclBuilder.AppendAttribute("experiments", exps) + } else { + // Vault expects a comma-separated list for VAULT_EXPERIMENTS + envVars["VAULT_EXPERIMENTS"] = strings.Join(exps, ",") + } + } + + // Numbers, bools, strings as top-level attributes + if val, ok := c.CacheSize.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("cache_size", val) + } + } + if val, ok := c.DisableCache.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("disable_cache", val) + } + } + if val, ok := c.DisableMlock.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("disable_mlock", val) + } else { + envVars["VAULT_DISABLE_MLOCK"] = strconv.FormatBool(val) + } + } + if val, ok := c.PluginDirectory.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("plugin_directory", val) + } else { + envVars["VAULT_PLUGIN_DIRECTORY"] = val + } + } + if val, ok := c.PluginTmpdir.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("plugin_tmpdir", val) + } else { + envVars["VAULT_PLUGIN_TMPDIR"] = val + } + } + if val, ok := c.PluginFileUID.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("plugin_file_uid", val) + } + } + if val, ok := c.PluginFilePermissions.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("plugin_file_permissions", val) + } + } + if val, ok := c.DefaultLeaseTTL.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("default_lease_ttl", val) + } else { + envVars["VAULT_DEFAULT_LEASE_TTL"] = val + } + } + if val, ok := c.MaxLeaseTTL.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("max_lease_ttl", val) + } else { + envVars["VAULT_MAX_LEASE_TTL"] = val + } + } + if val, ok := c.DefaultMaxRequestDuration.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("default_max_request_duration", val) + } + } + if val, ok := c.DetectDeadlocks.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("detect_deadlocks", val) + } + } + if val, ok := c.RawStorageEndpoint.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("raw_storage_endpoint", val) + } + } + if val, ok := c.IntrospectionEndpoint.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("introspection_endpoint", val) + } + } + if val, ok := c.PidFile.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("pid_file", val) + } else { + envVars["VAULT_PID_FILE"] = val + } + } + if val, ok := c.EnableResponseHeaderHostname.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("enable_response_header_hostname", val) + } + } + if val, ok := c.EnableResponseHeaderRaftNodeID.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("enable_response_header_raft_node_id", val) + } + } + if val, ok := c.LogFormat.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("log_format", val) + } else { + envVars["VAULT_LOG_FORMAT"] = val + } + } + if val, ok := c.LogFile.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("log_file", val) + } else { + envVars["VAULT_LOG_FILE"] = val + } + } + if val, ok := c.LogRotateDuration.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("log_rotate_duration", val) + } else { + envVars["VAULT_LOG_ROTATE_DURATION"] = val + } + } + if val, ok := c.LogRotateBytes.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("log_rotate_bytes", val) + } else { + envVars["VAULT_LOG_ROTATE_BYTES"] = fmt.Sprintf("%v", val) + } + } + if val, ok := c.LogRotateMaxFiles.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("log_rotate_max_files", val) + } else { + envVars["VAULT_LOG_ROTATE_MAX_FILES"] = fmt.Sprintf("%v", val) + } + } + if val, ok := c.ImpreciseLeaseRoleTracking.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("imprecise_lease_role_tracking", val) + } + } + if val, ok := c.EnablePostUnsealTrace.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("enable_post_unseal_trace", val) + } + } + if val, ok := c.PostUnsealTraceDirectory.Get(); ok { + if configMode == "file" { + hclBuilder.AppendAttribute("post_unseal_trace_directory", val) + } + } + return hclBuilder, envVars, nil } @@ -877,7 +1311,7 @@ func (s *vaultStartStateV1) startVault(ctx context.Context, transport it.Transpo // Manage the vault systemd service ourselves unless it has explicitly been // set that we should not. - if manage, set := s.ManageService.Get(); !set || (set && manage) { + if manage, set := s.ManageService.Get(); !set || manage { unit := systemd.Unit{ "Unit": { "Description": "HashiCorp Vault - A tool for managing secrets", From aac3b2f959794fca614c8b46a63acbd52456746f Mon Sep 17 00:00:00 2001 From: HamzaShili65 Date: Thu, 24 Jul 2025 11:27:34 -0700 Subject: [PATCH 3/8] fmt --- internal/plugin/resource_vault_start.go | 85 ++++++++++++------------- 1 file changed, 41 insertions(+), 44 deletions(-) diff --git a/internal/plugin/resource_vault_start.go b/internal/plugin/resource_vault_start.go index 666514f..136c800 100644 --- a/internal/plugin/resource_vault_start.go +++ b/internal/plugin/resource_vault_start.go @@ -63,18 +63,16 @@ type vaultStartStateV1 struct { } type vaultConfig struct { - ClusterName *tfString - APIAddr *tfString - ClusterAddr *tfString - Listener *vaultListenerConfig - LogLevel *tfString - Storage *vaultStorageConfig - Seal *vaultConfigBlock // Single seal configuration - Seals *vaultSealsConfig // HA Seal configuration - Telemetry *dynamicPseudoTypeBlock - UI *tfBool - - // Added fields from Vault config docs + ClusterName *tfString + APIAddr *tfString + ClusterAddr *tfString + Listener *vaultListenerConfig + LogLevel *tfString + Storage *vaultStorageConfig + Seal *vaultConfigBlock // Single seal configuration + Seals *vaultSealsConfig // HA Seal configuration + Telemetry *dynamicPseudoTypeBlock + UI *tfBool HAStorage *vaultStorageConfig UserLockout *vaultUserLockoutConfig Reporting *vaultReportingConfig @@ -583,17 +581,16 @@ func (c *vaultConfig) Terraform5Type() tftypes.Type { func (c *vaultConfig) attrs() map[string]tftypes.Type { return map[string]tftypes.Type{ - "api_addr": tftypes.String, - "cluster_addr": tftypes.String, - "cluster_name": c.ClusterName.TFType(), - "listener": c.Listener.Terraform5Type(), - "log_level": tftypes.String, - "storage": c.Storage.Terraform5Type(), - "seal": c.Seal.Terraform5Type(), - "seals": c.Seals.Terraform5Type(), - "telemetry": c.Telemetry.TFType(), - "ui": c.UI.TFType(), - + "api_addr": tftypes.String, + "cluster_addr": tftypes.String, + "cluster_name": c.ClusterName.TFType(), + "listener": c.Listener.Terraform5Type(), + "log_level": tftypes.String, + "storage": c.Storage.Terraform5Type(), + "seal": c.Seal.Terraform5Type(), + "seals": c.Seals.Terraform5Type(), + "telemetry": c.Telemetry.TFType(), + "ui": c.UI.TFType(), "ha_storage": c.HAStorage.Terraform5Type(), "user_lockout": c.UserLockout.Terraform5Type(), "reporting": c.Reporting.Terraform5Type(), @@ -663,24 +660,25 @@ func (c *vaultConfig) optionalAttrs() map[string]struct{} { } func (c *vaultConfig) Terraform5Value() tftypes.Value { + typ := tftypes.Object{ + AttributeTypes: c.attrs(), + } + telemetry, err := c.Telemetry.TFValue() if err != nil { panic(err) } - return tftypes.NewValue(tftypes.Object{ - AttributeTypes: c.attrs(), - }, map[string]tftypes.Value{ - "cluster_name": c.ClusterName.TFValue(), - "api_addr": c.APIAddr.TFValue(), - "cluster_addr": c.ClusterAddr.TFValue(), - "listener": c.Listener.Terraform5Value(), - "log_level": c.LogLevel.TFValue(), - "seal": c.Seal.Terraform5Value(), - "seals": c.Seals.Terraform5Value(), - "storage": c.Storage.Terraform5Value(), - "telemetry": telemetry, - "ui": c.UI.TFValue(), - + return tftypes.NewValue(typ, map[string]tftypes.Value{ + "cluster_name": c.ClusterName.TFValue(), + "api_addr": c.APIAddr.TFValue(), + "cluster_addr": c.ClusterAddr.TFValue(), + "listener": c.Listener.Terraform5Value(), + "log_level": c.LogLevel.TFValue(), + "seal": c.Seal.Terraform5Value(), + "seals": c.Seals.Terraform5Value(), + "storage": c.Storage.Terraform5Value(), + "telemetry": telemetry, + "ui": c.UI.TFValue(), "ha_storage": c.HAStorage.Terraform5Value(), "user_lockout": c.UserLockout.Terraform5Value(), "reporting": c.Reporting.Terraform5Value(), @@ -712,14 +710,14 @@ func (c *vaultConfig) Terraform5Value() tftypes.Value { }) } +// FromTerraform5Value unmarshals the value to the struct. func (c *vaultConfig) FromTerraform5Value(val tftypes.Value) error { vals, err := mapAttributesTo(val, map[string]any{ - "api_addr": c.APIAddr, - "cluster_addr": c.ClusterAddr, - "cluster_name": c.ClusterName, - "log_level": c.LogLevel, - "ui": c.UI, - + "api_addr": c.APIAddr, + "cluster_addr": c.ClusterAddr, + "cluster_name": c.ClusterName, + "log_level": c.LogLevel, + "ui": c.UI, "cache_size": c.CacheSize, "disable_cache": c.DisableCache, "disable_mlock": c.DisableMlock, @@ -789,7 +787,6 @@ func (c *vaultConfig) FromTerraform5Value(val tftypes.Value) error { } } - // New fields haStorage, ok := vals["ha_storage"] if ok { err = c.HAStorage.FromTerraform5Value(haStorage) From ecf80a4ba4d8bc6b52c79fd68d92d431b3bce077 Mon Sep 17 00:00:00 2001 From: HamzaShili65 Date: Thu, 24 Jul 2025 13:56:02 -0700 Subject: [PATCH 4/8] fmt --- internal/plugin/vault_config_experiments.go | 1 + internal/plugin/vault_config_reporting.go | 1 + internal/plugin/vault_config_user_lockout.go | 1 + 3 files changed, 3 insertions(+) diff --git a/internal/plugin/vault_config_experiments.go b/internal/plugin/vault_config_experiments.go index 7aa8216..aa28a77 100644 --- a/internal/plugin/vault_config_experiments.go +++ b/internal/plugin/vault_config_experiments.go @@ -5,6 +5,7 @@ package plugin import ( "fmt" + "github.com/hashicorp/terraform-plugin-go/tftypes" ) diff --git a/internal/plugin/vault_config_reporting.go b/internal/plugin/vault_config_reporting.go index c9847c8..c7c5b92 100644 --- a/internal/plugin/vault_config_reporting.go +++ b/internal/plugin/vault_config_reporting.go @@ -5,6 +5,7 @@ package plugin import ( "fmt" + "github.com/hashicorp/terraform-plugin-go/tftypes" ) diff --git a/internal/plugin/vault_config_user_lockout.go b/internal/plugin/vault_config_user_lockout.go index ffcb129..62a823a 100644 --- a/internal/plugin/vault_config_user_lockout.go +++ b/internal/plugin/vault_config_user_lockout.go @@ -5,6 +5,7 @@ package plugin import ( "fmt" + "github.com/hashicorp/terraform-plugin-go/tftypes" ) From de22276d5588af3df166e5428694bba35c40a5a5 Mon Sep 17 00:00:00 2001 From: HamzaShili65 Date: Thu, 24 Jul 2025 14:37:52 -0700 Subject: [PATCH 5/8] convert user_lockout and reporting struct types to dynamic-pseudo-type --- internal/plugin/vault_config_reporting.go | 153 ++++++++++++------- internal/plugin/vault_config_user_lockout.go | 75 +++++---- 2 files changed, 141 insertions(+), 87 deletions(-) diff --git a/internal/plugin/vault_config_reporting.go b/internal/plugin/vault_config_reporting.go index c7c5b92..5015a6e 100644 --- a/internal/plugin/vault_config_reporting.go +++ b/internal/plugin/vault_config_reporting.go @@ -13,6 +13,11 @@ type vaultReportingLicenseConfig struct { Enabled *tfBool BillingStartTimestamp *tfString DevelopmentCluster *tfBool + + RawValues map[string]tftypes.Value + RawValue tftypes.Value + Unknown bool + Null bool } func newVaultReportingLicenseConfig() *vaultReportingLicenseConfig { @@ -20,6 +25,8 @@ func newVaultReportingLicenseConfig() *vaultReportingLicenseConfig { Enabled: newTfBool(), BillingStartTimestamp: newTfString(), DevelopmentCluster: newTfBool(), + Unknown: false, + Null: true, } } @@ -27,8 +34,11 @@ type vaultReportingConfig struct { SnapshotRetentionTime *tfString DisableProductUsageReporting *tfBool License *vaultReportingLicenseConfig - Unknown bool - Null bool + + RawValues map[string]tftypes.Value + RawValue tftypes.Value + Unknown bool + Null bool } func newVaultReportingConfig() *vaultReportingConfig { @@ -54,42 +64,36 @@ func (s *vaultReportingConfig) FromTerraform5Value(val tftypes.Value) error { s.Unknown = true return nil } - vals := map[string]tftypes.Value{} - err := val.As(&vals) - if err != nil { + s.Null = false + s.Unknown = false + s.RawValue = val + s.RawValues = map[string]tftypes.Value{} + if err := val.As(&s.RawValues); err != nil { return err } - for k, v := range vals { + for k, v := range s.RawValues { switch k { case "snapshot_retention_time": - err = s.SnapshotRetentionTime.FromTFValue(v) + if err := s.SnapshotRetentionTime.FromTFValue(v); err != nil { + return err + } case "disable_product_usage_reporting": - err = s.DisableProductUsageReporting.FromTFValue(v) + if err := s.DisableProductUsageReporting.FromTFValue(v); err != nil { + return err + } case "license": - err = s.License.FromTerraform5Value(v) + if err := s.License.FromTerraform5Value(v); err != nil { + return err + } default: return fmt.Errorf("unknown reporting config key: %s", k) } - if err != nil { - return err - } } return nil } func (s *vaultReportingConfig) Terraform5Type() tftypes.Type { - return tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "snapshot_retention_time": tftypes.String, - "disable_product_usage_reporting": tftypes.Bool, - "license": newVaultReportingLicenseConfig().Terraform5Type(), - }, - OptionalAttributes: map[string]struct{}{ - "snapshot_retention_time": {}, - "disable_product_usage_reporting": {}, - "license": {}, - }, - } + return tftypes.DynamicPseudoType } func (s *vaultReportingConfig) Terraform5Value() tftypes.Value { @@ -99,11 +103,28 @@ func (s *vaultReportingConfig) Terraform5Value() tftypes.Value { if s.Unknown { return tftypes.NewValue(s.Terraform5Type(), tftypes.UnknownValue) } - return tftypes.NewValue(s.Terraform5Type(), map[string]tftypes.Value{ - "snapshot_retention_time": s.SnapshotRetentionTime.TFValue(), - "disable_product_usage_reporting": s.DisableProductUsageReporting.TFValue(), - "license": s.License.Terraform5Value(), - }) + attrs := map[string]tftypes.Type{} + vals := map[string]tftypes.Value{} + for name := range s.RawValues { + switch name { + case "snapshot_retention_time": + vals[name] = s.SnapshotRetentionTime.TFValue() + case "disable_product_usage_reporting": + vals[name] = s.DisableProductUsageReporting.TFValue() + case "license": + vals[name] = s.License.Terraform5Value() + } + attrs[name] = vals[name].Type() + } + if len(vals) == 0 { + return tftypes.NewValue(s.Terraform5Type(), nil) + } + if s.RawValue.Type().Is(tftypes.Map{}) { + for _, v := range vals { + return tftypes.NewValue(tftypes.Map{ElementType: v.Type()}, vals) + } + } + return tftypes.NewValue(tftypes.Object{AttributeTypes: attrs}, vals) } func (s *vaultReportingLicenseConfig) FromTerraform5Value(val tftypes.Value) error { @@ -111,53 +132,73 @@ func (s *vaultReportingLicenseConfig) FromTerraform5Value(val tftypes.Value) err return fmt.Errorf("cannot unmarshal %s into nil vaultReportingLicenseConfig", val.String()) } if val.IsNull() { + s.Null = true + s.Unknown = false return nil } if !val.IsKnown() { + s.Unknown = true return nil } - vals := map[string]tftypes.Value{} - err := val.As(&vals) - if err != nil { + s.Null = false + s.Unknown = false + s.RawValue = val + s.RawValues = map[string]tftypes.Value{} + if err := val.As(&s.RawValues); err != nil { return err } - for k, v := range vals { + for k, v := range s.RawValues { switch k { case "enabled": - err = s.Enabled.FromTFValue(v) + if err := s.Enabled.FromTFValue(v); err != nil { + return err + } case "billing_start_timestamp": - err = s.BillingStartTimestamp.FromTFValue(v) + if err := s.BillingStartTimestamp.FromTFValue(v); err != nil { + return err + } case "development_cluster": - err = s.DevelopmentCluster.FromTFValue(v) + if err := s.DevelopmentCluster.FromTFValue(v); err != nil { + return err + } default: return fmt.Errorf("unknown license config key: %s", k) } - if err != nil { - return err - } } return nil } func (s *vaultReportingLicenseConfig) Terraform5Type() tftypes.Type { - return tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "enabled": tftypes.Bool, - "billing_start_timestamp": tftypes.String, - "development_cluster": tftypes.Bool, - }, - OptionalAttributes: map[string]struct{}{ - "enabled": {}, - "billing_start_timestamp": {}, - "development_cluster": {}, - }, - } + return tftypes.DynamicPseudoType } func (s *vaultReportingLicenseConfig) Terraform5Value() tftypes.Value { - return tftypes.NewValue(s.Terraform5Type(), map[string]tftypes.Value{ - "enabled": s.Enabled.TFValue(), - "billing_start_timestamp": s.BillingStartTimestamp.TFValue(), - "development_cluster": s.DevelopmentCluster.TFValue(), - }) + if s.Null { + return tftypes.NewValue(s.Terraform5Type(), nil) + } + if s.Unknown { + return tftypes.NewValue(s.Terraform5Type(), tftypes.UnknownValue) + } + attrs := map[string]tftypes.Type{} + vals := map[string]tftypes.Value{} + for name := range s.RawValues { + switch name { + case "enabled": + vals[name] = s.Enabled.TFValue() + case "billing_start_timestamp": + vals[name] = s.BillingStartTimestamp.TFValue() + case "development_cluster": + vals[name] = s.DevelopmentCluster.TFValue() + } + attrs[name] = vals[name].Type() + } + if len(vals) == 0 { + return tftypes.NewValue(s.Terraform5Type(), nil) + } + if s.RawValue.Type().Is(tftypes.Map{}) { + for _, v := range vals { + return tftypes.NewValue(tftypes.Map{ElementType: v.Type()}, vals) + } + } + return tftypes.NewValue(tftypes.Object{AttributeTypes: attrs}, vals) } diff --git a/internal/plugin/vault_config_user_lockout.go b/internal/plugin/vault_config_user_lockout.go index 62a823a..8e15014 100644 --- a/internal/plugin/vault_config_user_lockout.go +++ b/internal/plugin/vault_config_user_lockout.go @@ -45,46 +45,41 @@ func (s *vaultUserLockoutConfig) FromTerraform5Value(val tftypes.Value) error { s.Unknown = true return nil } - vals := map[string]tftypes.Value{} - err := val.As(&vals) - if err != nil { + s.Null = false + s.Unknown = false + s.RawValue = val + s.RawValues = map[string]tftypes.Value{} + if err := val.As(&s.RawValues); err != nil { return err } - for k, v := range vals { + // Decode known fields + for k, v := range s.RawValues { switch k { case "lockout_threshold": - err = s.LockoutThreshold.FromTFValue(v) + if err := s.LockoutThreshold.FromTFValue(v); err != nil { + return err + } case "lockout_duration": - err = s.LockoutDuration.FromTFValue(v) + if err := s.LockoutDuration.FromTFValue(v); err != nil { + return err + } case "lockout_counter_reset": - err = s.LockoutCounterReset.FromTFValue(v) + if err := s.LockoutCounterReset.FromTFValue(v); err != nil { + return err + } case "disable_lockout": - err = s.DisableLockout.FromTFValue(v) + if err := s.DisableLockout.FromTFValue(v); err != nil { + return err + } default: return fmt.Errorf("unknown user_lockout config key: %s", k) } - if err != nil { - return err - } } return nil } func (s *vaultUserLockoutConfig) Terraform5Type() tftypes.Type { - return tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "lockout_threshold": tftypes.String, - "lockout_duration": tftypes.String, - "lockout_counter_reset": tftypes.String, - "disable_lockout": tftypes.Bool, - }, - OptionalAttributes: map[string]struct{}{ - "lockout_threshold": {}, - "lockout_duration": {}, - "lockout_counter_reset": {}, - "disable_lockout": {}, - }, - } + return tftypes.DynamicPseudoType } func (s *vaultUserLockoutConfig) Terraform5Value() tftypes.Value { @@ -94,10 +89,28 @@ func (s *vaultUserLockoutConfig) Terraform5Value() tftypes.Value { if s.Unknown { return tftypes.NewValue(s.Terraform5Type(), tftypes.UnknownValue) } - return tftypes.NewValue(s.Terraform5Type(), map[string]tftypes.Value{ - "lockout_threshold": s.LockoutThreshold.TFValue(), - "lockout_duration": s.LockoutDuration.TFValue(), - "lockout_counter_reset": s.LockoutCounterReset.TFValue(), - "disable_lockout": s.DisableLockout.TFValue(), - }) + attrs := map[string]tftypes.Type{} + vals := map[string]tftypes.Value{} + for name := range s.RawValues { + switch name { + case "lockout_threshold": + vals[name] = s.LockoutThreshold.TFValue() + case "lockout_duration": + vals[name] = s.LockoutDuration.TFValue() + case "lockout_counter_reset": + vals[name] = s.LockoutCounterReset.TFValue() + case "disable_lockout": + vals[name] = s.DisableLockout.TFValue() + } + attrs[name] = vals[name].Type() + } + if len(vals) == 0 { + return tftypes.NewValue(s.Terraform5Type(), nil) + } + if s.RawValue.Type().Is(tftypes.Map{}) { + for _, v := range vals { + return tftypes.NewValue(tftypes.Map{ElementType: v.Type()}, vals) + } + } + return tftypes.NewValue(tftypes.Object{AttributeTypes: attrs}, vals) } From 85f513d073dacd97daeab46498d7221087c37d62 Mon Sep 17 00:00:00 2001 From: HamzaShili65 Date: Thu, 24 Jul 2025 15:05:30 -0700 Subject: [PATCH 6/8] fmt --- internal/plugin/resource_vault_start.go | 4 ++-- internal/plugin/vault_config_experiments.go | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/plugin/resource_vault_start.go b/internal/plugin/resource_vault_start.go index 136c800..e5c7f52 100644 --- a/internal/plugin/resource_vault_start.go +++ b/internal/plugin/resource_vault_start.go @@ -1172,14 +1172,14 @@ func (c *vaultConfig) Render(configMode string) (*hcl.Builder, map[string]string if configMode == "file" { hclBuilder.AppendAttribute("log_rotate_bytes", val) } else { - envVars["VAULT_LOG_ROTATE_BYTES"] = fmt.Sprintf("%v", val) + envVars["VAULT_LOG_ROTATE_BYTES"] = strconv.Itoa(val) } } if val, ok := c.LogRotateMaxFiles.Get(); ok { if configMode == "file" { hclBuilder.AppendAttribute("log_rotate_max_files", val) } else { - envVars["VAULT_LOG_ROTATE_MAX_FILES"] = fmt.Sprintf("%v", val) + envVars["VAULT_LOG_ROTATE_MAX_FILES"] = strconv.Itoa(val) } } if val, ok := c.ImpreciseLeaseRoleTracking.Get(); ok { diff --git a/internal/plugin/vault_config_experiments.go b/internal/plugin/vault_config_experiments.go index aa28a77..159bd30 100644 --- a/internal/plugin/vault_config_experiments.go +++ b/internal/plugin/vault_config_experiments.go @@ -32,6 +32,7 @@ func (s *vaultExperimentsConfig) FromTerraform5Value(val tftypes.Value) error { if val.IsNull() { s.Null = true s.Unknown = false + return nil } if !val.IsKnown() { @@ -49,6 +50,7 @@ func (s *vaultExperimentsConfig) FromTerraform5Value(val tftypes.Value) error { ts.Set(exp) s.Experiments = append(s.Experiments, ts) } + return nil } From 2ed6b6cb993a9d5a56c67d1060a979cd7c0e2a4c Mon Sep 17 00:00:00 2001 From: HamzaShili65 Date: Thu, 24 Jul 2025 19:25:43 -0700 Subject: [PATCH 7/8] extend interfaces to add a set method --- internal/plugin/vault_config_experiments.go | 31 ++++++++++-- internal/plugin/vault_config_reporting.go | 50 ++++++++++++++++++++ internal/plugin/vault_config_user_lockout.go | 31 ++++++++++++ 3 files changed, 109 insertions(+), 3 deletions(-) diff --git a/internal/plugin/vault_config_experiments.go b/internal/plugin/vault_config_experiments.go index 159bd30..87662ca 100644 --- a/internal/plugin/vault_config_experiments.go +++ b/internal/plugin/vault_config_experiments.go @@ -65,11 +65,36 @@ func (s *vaultExperimentsConfig) Terraform5Value() tftypes.Value { if s.Unknown { return tftypes.NewValue(s.Terraform5Type(), tftypes.UnknownValue) } - exps := []string{} + // Build slice of tftypes.Value for list + vals := []tftypes.Value{} for _, ts := range s.Experiments { if val, ok := ts.Get(); ok { - exps = append(exps, val) + vals = append(vals, tftypes.NewValue(tftypes.String, val)) } } - return tftypes.NewValue(s.Terraform5Type(), exps) + return tftypes.NewValue(s.Terraform5Type(), vals) +} + +// Add Set method and configSet for experiments + +type vaultExperimentsConfigSet struct { + Experiments []string +} + +func newVaultExperimentsConfigSet(experiments []string) *vaultExperimentsConfigSet { + return &vaultExperimentsConfigSet{experiments} +} + +func (s *vaultExperimentsConfig) Set(set *vaultExperimentsConfigSet) { + if s == nil || set == nil { + return + } + s.Null = false + s.Unknown = false + s.Experiments = []*tfString{} + for _, exp := range set.Experiments { + ts := newTfString() + ts.Set(exp) + s.Experiments = append(s.Experiments, ts) + } } diff --git a/internal/plugin/vault_config_reporting.go b/internal/plugin/vault_config_reporting.go index 5015a6e..91a6ce2 100644 --- a/internal/plugin/vault_config_reporting.go +++ b/internal/plugin/vault_config_reporting.go @@ -202,3 +202,53 @@ func (s *vaultReportingLicenseConfig) Terraform5Value() tftypes.Value { } return tftypes.NewValue(tftypes.Object{AttributeTypes: attrs}, vals) } + +// Add Set methods and configSet types for reporting + +type vaultReportingLicenseConfigSet struct { + Enabled bool + BillingStartTimestamp string + DevelopmentCluster bool +} + +func newVaultReportingLicenseConfigSet(enabled bool, billingTimestamp string, developmentCluster bool) *vaultReportingLicenseConfigSet { + return &vaultReportingLicenseConfigSet{enabled, billingTimestamp, developmentCluster} +} + +func (s *vaultReportingLicenseConfig) Set(set *vaultReportingLicenseConfigSet) { + if s == nil || set == nil { + return + } + s.Null = false + s.Unknown = false + s.Enabled.Set(set.Enabled) + s.BillingStartTimestamp.Set(set.BillingStartTimestamp) + s.DevelopmentCluster.Set(set.DevelopmentCluster) +} + +// ConfigSet for vaultReportingConfig + +type vaultReportingConfigSet struct { + SnapshotRetentionTime string + DisableProductUsageReporting bool + License *vaultReportingLicenseConfigSet +} + +func newVaultReportingConfigSet(snapshotRetentionTime string, disableReporting bool, license *vaultReportingLicenseConfigSet) *vaultReportingConfigSet { + return &vaultReportingConfigSet{snapshotRetentionTime, disableReporting, license} +} + +func (s *vaultReportingConfig) Set(set *vaultReportingConfigSet) { + if s == nil || set == nil { + return + } + s.Null = false + s.Unknown = false + if set.SnapshotRetentionTime != "" { + s.SnapshotRetentionTime.Set(set.SnapshotRetentionTime) + } + s.DisableProductUsageReporting.Set(set.DisableProductUsageReporting) + if set.License != nil { + s.License.Set(set.License) + } +} diff --git a/internal/plugin/vault_config_user_lockout.go b/internal/plugin/vault_config_user_lockout.go index 8e15014..edd5d7b 100644 --- a/internal/plugin/vault_config_user_lockout.go +++ b/internal/plugin/vault_config_user_lockout.go @@ -114,3 +114,34 @@ func (s *vaultUserLockoutConfig) Terraform5Value() tftypes.Value { } return tftypes.NewValue(tftypes.Object{AttributeTypes: attrs}, vals) } + +// Add Set method and configSet for user_lockout + +type vaultUserLockoutConfigSet struct { + LockoutThreshold string + LockoutDuration string + LockoutCounterReset string + DisableLockout bool +} + +func newVaultUserLockoutConfigSet(threshold, duration, counterReset string, disableLockout bool) *vaultUserLockoutConfigSet { + return &vaultUserLockoutConfigSet{threshold, duration, counterReset, disableLockout} +} + +func (s *vaultUserLockoutConfig) Set(set *vaultUserLockoutConfigSet) { + if s == nil || set == nil { + return + } + s.Null = false + s.Unknown = false + if set.LockoutThreshold != "" { + s.LockoutThreshold.Set(set.LockoutThreshold) + } + if set.LockoutDuration != "" { + s.LockoutDuration.Set(set.LockoutDuration) + } + if set.LockoutCounterReset != "" { + s.LockoutCounterReset.Set(set.LockoutCounterReset) + } + s.DisableLockout.Set(set.DisableLockout) +} From 7580008d11bf4c9c1f8ae96bf15b1ccd8b7d89ba Mon Sep 17 00:00:00 2001 From: HamzaShili65 Date: Thu, 24 Jul 2025 19:27:29 -0700 Subject: [PATCH 8/8] extend unit and acceptance tests to test all vault's configs --- internal/plugin/resource_vault_start_test.go | 173 +++++++++++++++++++ 1 file changed, 173 insertions(+) diff --git a/internal/plugin/resource_vault_start_test.go b/internal/plugin/resource_vault_start_test.go index f6f6c4e..6174857 100644 --- a/internal/plugin/resource_vault_start_test.go +++ b/internal/plugin/resource_vault_start_test.go @@ -68,6 +68,48 @@ func TestVaultStartConfigOptionalAttrs(t *testing.T) { "usage_gauge_period": "30m", "maximum_gague_cardinality": 100, }) + vaultCfg.UI.Set(true) + vaultCfg.CacheSize.Set(42) + vaultCfg.DisableCache.Set(true) + vaultCfg.DisableMlock.Set(true) + vaultCfg.PluginDirectory.Set("/opt/plugins") + vaultCfg.PluginTmpdir.Set("/tmp/plugins") + vaultCfg.PluginFileUID.Set(1001) + vaultCfg.PluginFilePermissions.Set(0644) + vaultCfg.DefaultLeaseTTL.Set("30s") + vaultCfg.MaxLeaseTTL.Set("1h") + vaultCfg.DefaultMaxRequestDuration.Set("2m") + vaultCfg.DetectDeadlocks.Set(true) + vaultCfg.RawStorageEndpoint.Set("/metrics") + vaultCfg.IntrospectionEndpoint.Set("/introspect") + vaultCfg.PidFile.Set("/var/run/vault.pid") + vaultCfg.EnableResponseHeaderHostname.Set(true) + vaultCfg.EnableResponseHeaderRaftNodeID.Set(true) + vaultCfg.LogFormat.Set("json") + vaultCfg.LogFile.Set("/var/log/vault.log") + vaultCfg.LogRotateDuration.Set("5m") + vaultCfg.LogRotateBytes.Set(1048576) + vaultCfg.LogRotateMaxFiles.Set(7) + vaultCfg.ImpreciseLeaseRoleTracking.Set(true) + vaultCfg.EnablePostUnsealTrace.Set(true) + vaultCfg.PostUnsealTraceDirectory.Set("/var/lib/vault/traces") + // Set user_lockout block using constructor + vaultCfg.UserLockout.Set(newVaultUserLockoutConfigSet( + "3", + "5m", + "10m", + true)) + // Set reporting block using constructor + vaultCfg.Reporting.Set(newVaultReportingConfigSet( + "1h", + false, + newVaultReportingLicenseConfigSet( + true, + "2025-07-24T00:00:00Z", + false), + )) + // Set experiments list + vaultCfg.Experiments.Set(newVaultExperimentsConfigSet([]string{"expA", "expB"})) // Make sure we can create a dynamic value with optional attrs val := vaultCfg.Terraform5Value() @@ -106,6 +148,30 @@ func TestAccResourceVaultStart(t *testing.T) { cluster_name = "{{.Config.ClusterName.Value}}" log_level = "{{.Config.LogLevel.Value}}" ui = true + cache_size = {{.Config.CacheSize.Value}} + disable_cache = {{.Config.DisableCache.Value}} + disable_mlock = {{.Config.DisableMlock.Value}} + plugin_directory = "{{.Config.PluginDirectory.Value}}" + plugin_tmpdir = "{{.Config.PluginTmpdir.Value}}" + plugin_file_uid = {{.Config.PluginFileUID.Value}} + plugin_file_permissions = {{.Config.PluginFilePermissions.Value}} + default_lease_ttl = "{{.Config.DefaultLeaseTTL.Value}}" + max_lease_ttl = "{{.Config.MaxLeaseTTL.Value}}" + default_max_request_duration = "{{.Config.DefaultMaxRequestDuration.Value}}" + detect_deadlocks = {{.Config.DetectDeadlocks.Value}} + raw_storage_endpoint = "{{.Config.RawStorageEndpoint.Value}}" + introspection_endpoint = "{{.Config.IntrospectionEndpoint.Value}}" + pid_file = "{{.Config.PidFile.Value}}" + enable_response_header_hostname = {{.Config.EnableResponseHeaderHostname.Value}} + enable_response_header_raft_node_id = {{.Config.EnableResponseHeaderRaftNodeID.Value}} + log_format = "{{.Config.LogFormat.Value}}" + log_file = "{{.Config.LogFile.Value}}" + log_rotate_duration = "{{.Config.LogRotateDuration.Value}}" + log_rotate_bytes = {{.Config.LogRotateBytes.Value}} + log_rotate_max_files = {{.Config.LogRotateMaxFiles.Value}} + imprecise_lease_role_tracking = {{.Config.ImpreciseLeaseRoleTracking.Value}} + enable_post_unseal_trace = {{.Config.EnablePostUnsealTrace.Value}} + post_unseal_trace_directory = "{{.Config.PostUnsealTraceDirectory.Value}}" listener = { type = "{{.Config.Listener.Type.Value}}" @@ -169,6 +235,16 @@ func TestAccResourceVaultStart(t *testing.T) { } } + {{if .Config.HAStorage.Type.Value -}} + ha_storage = { + type = "{{.Config.HAStorage.Type.Value}}" + attributes = { {{range $name, $val := .Config.HAStorage.Attrs.Object.Value -}} + {{$name}} = "{{$val}}" + {{end -}} + } + } + {{end -}} + {{if .Config.Telemetry.Object.Value -}} telemetry = { {{range $name, $val := .Config.Telemetry.Object.Value -}} @@ -176,6 +252,27 @@ func TestAccResourceVaultStart(t *testing.T) { {{end}} } {{end -}} + {{if or .Config.UserLockout.LockoutThreshold.Value .Config.UserLockout.LockoutDuration.Value .Config.UserLockout.LockoutCounterReset.Value .Config.UserLockout.DisableLockout.Value -}} + user_lockout = { + {{if .Config.UserLockout.LockoutThreshold.Value}}lockout_threshold = "{{.Config.UserLockout.LockoutThreshold.Value}}"{{end}} + {{if .Config.UserLockout.LockoutDuration.Value}}lockout_duration = "{{.Config.UserLockout.LockoutDuration.Value}}"{{end}} + {{if .Config.UserLockout.LockoutCounterReset.Value}}lockout_counter_reset = "{{.Config.UserLockout.LockoutCounterReset.Value}}"{{end}} + {{if .Config.UserLockout.DisableLockout.Value}}disable_lockout = {{.Config.UserLockout.DisableLockout.Value}}{{end}} + } + {{end}} + {{if or .Config.Reporting.SnapshotRetentionTime.Value .Config.Reporting.DisableProductUsageReporting.Value .Config.Reporting.License.Enabled.Value .Config.Reporting.License.BillingStartTimestamp.Value .Config.Reporting.License.DevelopmentCluster.Value -}} + reporting = { + {{if .Config.Reporting.SnapshotRetentionTime.Value}}snapshot_retention_time = "{{.Config.Reporting.SnapshotRetentionTime.Value}}"{{end}} + {{if .Config.Reporting.DisableProductUsageReporting.Value}}disable_product_usage_reporting = {{.Config.Reporting.DisableProductUsageReporting.Value}}{{end}} + {{if or .Config.Reporting.License.Enabled.Value .Config.Reporting.License.BillingStartTimestamp.Value .Config.Reporting.License.DevelopmentCluster.Value -}} + license = { + {{if .Config.Reporting.License.Enabled.Value}}enabled = {{.Config.Reporting.License.Enabled.Value}}{{end}} + {{if .Config.Reporting.License.BillingStartTimestamp.Value}}billing_start_timestamp = "{{.Config.Reporting.License.BillingStartTimestamp.Value}}"{{end}} + {{if .Config.Reporting.License.DevelopmentCluster.Value}}development_cluster = {{.Config.Reporting.License.DevelopmentCluster.Value}}{{end}} + } + {{end}} + } + {{end}} } {{ renderTransport .Transport }} @@ -231,6 +328,52 @@ func TestAccResourceVaultStart(t *testing.T) { "usage_gauge_period": "30m", "maximum_gague_cardinality": 100, }) + // Set experiments list + vaultStart.Config.Experiments.Set(newVaultExperimentsConfigSet([]string{"expA", "expB"})) + // Set top level simple config fields + vaultStart.Config.CacheSize.Set(42) + vaultStart.Config.DisableCache.Set(true) + vaultStart.Config.DisableMlock.Set(true) + vaultStart.Config.PluginDirectory.Set("/opt/plugins") + vaultStart.Config.PluginTmpdir.Set("/tmp/plugins") + vaultStart.Config.PluginFileUID.Set(1001) + vaultStart.Config.PluginFilePermissions.Set(0644) + vaultStart.Config.DefaultLeaseTTL.Set("30s") + vaultStart.Config.MaxLeaseTTL.Set("1h") + vaultStart.Config.DefaultMaxRequestDuration.Set("2m") + vaultStart.Config.DetectDeadlocks.Set(true) + vaultStart.Config.RawStorageEndpoint.Set("/metrics") + vaultStart.Config.IntrospectionEndpoint.Set("/introspect") + vaultStart.Config.PidFile.Set("/var/run/vault.pid") + vaultStart.Config.EnableResponseHeaderHostname.Set(true) + vaultStart.Config.EnableResponseHeaderRaftNodeID.Set(true) + vaultStart.Config.LogFormat.Set("json") + vaultStart.Config.LogFile.Set("/var/log/vault.log") + vaultStart.Config.LogRotateDuration.Set("5m") + vaultStart.Config.LogRotateBytes.Set(1048576) + vaultStart.Config.LogRotateMaxFiles.Set(7) + vaultStart.Config.ImpreciseLeaseRoleTracking.Set(true) + vaultStart.Config.EnablePostUnsealTrace.Set(true) + vaultStart.Config.PostUnsealTraceDirectory.Set("/var/lib/vault/traces") + // Set HA storage block + vaultStart.Config.HAStorage.Set(newVaultStorageConfigSet("raft", map[string]any{"path": "ha_path"}, nil)) + // Set user_lockout block + vaultStart.Config.UserLockout.Set(newVaultUserLockoutConfigSet( + "3", + "5m", + "10m", + true)) + // Set reporting block + vaultStart.Config.Reporting.Set(newVaultReportingConfigSet( + "1h", + false, + newVaultReportingLicenseConfigSet( + true, + "2025-07-24T00:00:00Z", + false), + )) + // Set experiments list + vaultStart.Config.Experiments.Set(newVaultExperimentsConfigSet([]string{"expA", "expB"})) vaultStart.License.Set("some-license-key") vaultStart.SystemdUnitName.Set("vaulter") vaultStart.Username.Set("vault") @@ -263,6 +406,8 @@ func TestAccResourceVaultStart(t *testing.T) { resource.TestCheckResourceAttr("enos_vault_start.foo", "config.storage.attributes.path", "vault"), resource.TestCheckResourceAttr("enos_vault_start.foo", "config.storage.retry_join.auto_join_scheme", "https"), resource.TestCheckResourceAttr("enos_vault_start.foo", "config.storage.retry_join.auto_join", "provider=aws tag_key=join tag_value=vault"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.ha_storage.type", "raft"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.ha_storage.attributes.path", "ha_path"), resource.TestCheckResourceAttr("enos_vault_start.foo", "config.seal.type", "awskms"), resource.TestCheckResourceAttr("enos_vault_start.foo", "config.seal.attributes.kms_key_id", "some-key-id"), resource.TestCheckResourceAttr("enos_vault_start.foo", "config.seals[0].type", "awskms"), @@ -276,6 +421,34 @@ func TestAccResourceVaultStart(t *testing.T) { resource.TestCheckResourceAttr("enos_vault_start.foo", "config.username", "vaulter"), resource.TestCheckResourceAttr("enos_vault_start.foo", "transport.ssh.user", "ubuntu"), resource.TestCheckResourceAttr("enos_vault_start.foo", "transport.ssh.host", "localhost"), + // experiments + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.experiments.0", "expA"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.experiments.1", "expB"), + // top-level simple config fields + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.cache_size", "42"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.disable_cache", "true"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.disable_mlock", "true"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.plugin_directory", "/opt/plugins"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.plugin_tmpdir", "/tmp/plugins"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.plugin_file_uid", "1001"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.plugin_file_permissions", "420"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.default_lease_ttl", "30s"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.max_lease_ttl", "1h"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.default_max_request_duration", "2m"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.detect_deadlocks", "true"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.raw_storage_endpoint", "/metrics"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.introspection_endpoint", "/introspect"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.pid_file", "/var/run/vault.pid"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.enable_response_header_hostname", "true"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.enable_response_header_raft_node_id", "true"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.log_format", "json"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.log_file", "/var/log/vault.log"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.log_rotate_duration", "5m"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.log_rotate_bytes", "1048576"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.log_rotate_max_files", "7"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.imprecise_lease_role_tracking", "true"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.enable_post_unseal_trace", "true"), + resource.TestCheckResourceAttr("enos_vault_start.foo", "config.post_unseal_trace_directory", "/var/lib/vault/traces"), ), false, })