diff --git a/CHANGELOG.md b/CHANGELOG.md index a14d2f7e2..7d4e1c89c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - Add `headers` for the provider connection ([#1057](https://github.com/elastic/terraform-provider-elasticstack/pull/1057)) - Migrate `elasticstack_elasticsearch_system_user` resource to Terraform plugin framework ([#1154](https://github.com/elastic/terraform-provider-elasticstack/pull/1154)) - Add custom `endpoint` configuration support for snapshot repository setup ([#1158](https://github.com/elastic/terraform-provider-elasticstack/pull/1158)) +- Add `description` to `elasticstack_kibana_security_role` ([#1172](https://github.com/elastic/terraform-provider-elasticstack/issues/1172)) ## [0.11.15] - 2025-04-23 diff --git a/docs/data-sources/kibana_security_role.md b/docs/data-sources/kibana_security_role.md index 58904b2f8..f2db9f711 100644 --- a/docs/data-sources/kibana_security_role.md +++ b/docs/data-sources/kibana_security_role.md @@ -32,6 +32,7 @@ data "elasticstack_kibana_security_role" "example" { ### Optional +- `description` (String) Description for the role - `metadata` (String) Optional meta-data. ### Read-Only diff --git a/docs/resources/kibana_security_role.md b/docs/resources/kibana_security_role.md index 16b3c7564..0d4ef2e05 100644 --- a/docs/resources/kibana_security_role.md +++ b/docs/resources/kibana_security_role.md @@ -124,6 +124,7 @@ resource "elasticstack_kibana_security_role" "example" { ### Optional +- `description` (String) Optional description for the role - `kibana` (Block Set) The list of objects that specify the Kibana privileges for the role. (see [below for nested schema](#nestedblock--kibana)) - `metadata` (String) Optional meta-data. diff --git a/internal/elasticsearch/security/role.go b/internal/elasticsearch/security/role.go index 41953ce3f..bbebeba6c 100644 --- a/internal/elasticsearch/security/role.go +++ b/internal/elasticsearch/security/role.go @@ -17,8 +17,10 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) -var minSupportedRemoteIndicesVersion = version.Must(version.NewVersion("8.10.0")) -var minSupportedDescriptionVersion = version.Must(version.NewVersion("8.15.0")) +var ( + MinSupportedRemoteIndicesVersion = version.Must(version.NewVersion("8.10.0")) + MinSupportedDescriptionVersion = version.Must(version.NewVersion("8.15.0")) +) func ResourceRole() *schema.Resource { roleSchema := map[string]*schema.Schema{ @@ -268,8 +270,8 @@ func resourceSecurityRolePut(ctx context.Context, d *schema.ResourceData, meta i // Add description to the role if v, ok := d.GetOk("description"); ok { // Return an error if the server version is less than the minimum supported version - if serverVersion.LessThan(minSupportedDescriptionVersion) { - return diag.FromErr(fmt.Errorf("'description' is supported only for Elasticsearch v%s and above", minSupportedDescriptionVersion.String())) + if serverVersion.LessThan(MinSupportedDescriptionVersion) { + return diag.FromErr(fmt.Errorf("'description' is supported only for Elasticsearch v%s and above", MinSupportedDescriptionVersion.String())) } description := v.(string) @@ -379,8 +381,8 @@ func resourceSecurityRolePut(ctx context.Context, d *schema.ResourceData, meta i if v, ok := d.GetOk("remote_indices"); ok { definedRemoteIndices := v.(*schema.Set) - if definedRemoteIndices.Len() > 0 && serverVersion.LessThan(minSupportedRemoteIndicesVersion) { - return diag.FromErr(fmt.Errorf("'remote_indices' is supported only for Elasticsearch v%s and above", minSupportedRemoteIndicesVersion.String())) + if definedRemoteIndices.Len() > 0 && serverVersion.LessThan(MinSupportedRemoteIndicesVersion) { + return diag.FromErr(fmt.Errorf("'remote_indices' is supported only for Elasticsearch v%s and above", MinSupportedRemoteIndicesVersion.String())) } remoteIndices := make([]models.RemoteIndexPerms, definedRemoteIndices.Len()) for i, idx := range definedRemoteIndices.List() { diff --git a/internal/elasticsearch/security/role_data_source_test.go b/internal/elasticsearch/security/role_data_source_test.go index aeccdf30e..0af0d4841 100644 --- a/internal/elasticsearch/security/role_data_source_test.go +++ b/internal/elasticsearch/security/role_data_source_test.go @@ -5,6 +5,7 @@ import ( "github.com/elastic/terraform-provider-elasticstack/internal/acctest" "github.com/elastic/terraform-provider-elasticstack/internal/acctest/checks" + "github.com/elastic/terraform-provider-elasticstack/internal/elasticsearch/security" "github.com/elastic/terraform-provider-elasticstack/internal/versionutils" "github.com/hashicorp/go-version" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -51,7 +52,7 @@ func TestAccDataSourceSecurityRole(t *testing.T) { }, { Config: testAccDataSourceSecurityRoleWithDescription, - SkipFunc: versionutils.CheckIfVersionIsUnsupported(minSupportedDescriptionVersion), + SkipFunc: versionutils.CheckIfVersionIsUnsupported(security.MinSupportedDescriptionVersion), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.elasticstack_elasticsearch_security_role.test", "name", "data_source_test"), resource.TestCheckTypeSetElemAttr("data.elasticstack_elasticsearch_security_role.test", "cluster.*", "all"), diff --git a/internal/elasticsearch/security/role_test.go b/internal/elasticsearch/security/role_test.go index aa00155c3..788764582 100644 --- a/internal/elasticsearch/security/role_test.go +++ b/internal/elasticsearch/security/role_test.go @@ -6,16 +6,13 @@ import ( "github.com/elastic/terraform-provider-elasticstack/internal/acctest" "github.com/elastic/terraform-provider-elasticstack/internal/clients" + "github.com/elastic/terraform-provider-elasticstack/internal/elasticsearch/security" "github.com/elastic/terraform-provider-elasticstack/internal/versionutils" - "github.com/hashicorp/go-version" sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) -var minSupportedRemoteIndicesVersion = version.Must(version.NewSemver("8.10.0")) -var minSupportedDescriptionVersion = version.Must(version.NewVersion("8.15.0")) - func TestAccResourceSecurityRole(t *testing.T) { // generate a random username roleName := sdkacctest.RandStringFromCharSet(10, sdkacctest.CharSetAlphaNum) @@ -53,7 +50,7 @@ func TestAccResourceSecurityRole(t *testing.T) { ), }, { - SkipFunc: versionutils.CheckIfVersionIsUnsupported(minSupportedRemoteIndicesVersion), + SkipFunc: versionutils.CheckIfVersionIsUnsupported(security.MinSupportedRemoteIndicesVersion), Config: testAccResourceSecurityRoleRemoteIndicesCreate(roleNameRemoteIndices), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("elasticstack_elasticsearch_security_role.test", "name", roleNameRemoteIndices), @@ -68,7 +65,7 @@ func TestAccResourceSecurityRole(t *testing.T) { ), }, { - SkipFunc: versionutils.CheckIfVersionIsUnsupported(minSupportedRemoteIndicesVersion), + SkipFunc: versionutils.CheckIfVersionIsUnsupported(security.MinSupportedRemoteIndicesVersion), Config: testAccResourceSecurityRoleRemoteIndicesUpdate(roleNameRemoteIndices), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("elasticstack_elasticsearch_security_role.test", "name", roleNameRemoteIndices), @@ -84,7 +81,7 @@ func TestAccResourceSecurityRole(t *testing.T) { ), }, { - SkipFunc: versionutils.CheckIfVersionIsUnsupported(minSupportedDescriptionVersion), + SkipFunc: versionutils.CheckIfVersionIsUnsupported(security.MinSupportedDescriptionVersion), Config: testAccResourceSecurityRoleDescriptionCreate(roleNameDescription), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("elasticstack_elasticsearch_security_role.test", "name", roleNameDescription), @@ -92,7 +89,7 @@ func TestAccResourceSecurityRole(t *testing.T) { ), }, { - SkipFunc: versionutils.CheckIfVersionIsUnsupported(minSupportedDescriptionVersion), + SkipFunc: versionutils.CheckIfVersionIsUnsupported(security.MinSupportedDescriptionVersion), Config: testAccResourceSecurityRoleDescriptionUpdate(roleNameDescription), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("elasticstack_elasticsearch_security_role.test", "name", roleNameDescription), diff --git a/internal/kibana/role.go b/internal/kibana/role.go index c19aed808..0138545b1 100644 --- a/internal/kibana/role.go +++ b/internal/kibana/role.go @@ -15,7 +15,10 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) -var minSupportedRemoteIndicesVersion = version.Must(version.NewVersion("8.10.0")) +var ( + minSupportedRemoteIndicesVersion = version.Must(version.NewVersion("8.10.0")) + minSupportedDescriptionVersion = version.Must(version.NewVersion("8.15.0")) +) func ResourceRole() *schema.Resource { roleSchema := map[string]*schema.Schema{ @@ -232,6 +235,11 @@ func ResourceRole() *schema.Resource { ValidateFunc: validation.StringIsJSON, DiffSuppressFunc: utils.DiffJsonSuppress, }, + "description": { + Description: "Optional description for the role", + Type: schema.TypeString, + Optional: true, + }, } return &schema.Resource{ @@ -293,6 +301,14 @@ func resourceRoleUpsert(ctx context.Context, d *schema.ResourceData, meta interf } } + if v, ok := d.GetOk("description"); ok { + if serverVersion.LessThan(minSupportedDescriptionVersion) { + return diag.FromErr(fmt.Errorf("'description' is supported only for Kibana v%s and above", minSupportedDescriptionVersion.String())) + } + + kibanaRole.Description = v.(string) + } + roleManageResponse, err := kibana.KibanaRoleManagement.CreateOrUpdate(&kibanaRole) if err != nil { return diag.FromErr(err) @@ -334,6 +350,9 @@ func resourceRoleRead(ctx context.Context, d *schema.ResourceData, meta interfac if err := d.Set("kibana", flattenKibanaRoleKibanaData(&role.Kibana)); err != nil { return diag.FromErr(err) } + if err := d.Set("description", role.Description); err != nil { + return diag.FromErr(err) + } if role.Metadata != nil { metadata, err := json.Marshal(role.Metadata) if err != nil { diff --git a/internal/kibana/role_data_source.go b/internal/kibana/role_data_source.go index 735f94113..43cdb711e 100644 --- a/internal/kibana/role_data_source.go +++ b/internal/kibana/role_data_source.go @@ -217,6 +217,11 @@ func DataSourceRole() *schema.Resource { ValidateFunc: validation.StringIsJSON, DiffSuppressFunc: utils.DiffJsonSuppress, }, + "description": { + Description: "Description for the role", + Type: schema.TypeString, + Optional: true, + }, } return &schema.Resource{ diff --git a/internal/kibana/role_test.go b/internal/kibana/role_test.go index 70669df32..4b48087d8 100644 --- a/internal/kibana/role_test.go +++ b/internal/kibana/role_test.go @@ -19,6 +19,7 @@ func TestAccResourceKibanaSecurityRole(t *testing.T) { roleName := sdkacctest.RandStringFromCharSet(10, sdkacctest.CharSetAlphaNum) roleNameRemoteIndices := sdkacctest.RandStringFromCharSet(10, sdkacctest.CharSetAlphaNum) minSupportedRemoteIndicesVersion := version.Must(version.NewSemver("8.10.0")) + minSupportedDescriptionVersion := version.Must(version.NewVersion("8.15.0")) resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -48,6 +49,16 @@ func TestAccResourceKibanaSecurityRole(t *testing.T) { checks.TestCheckResourceListAttr("elasticstack_kibana_security_role.test", "kibana.0.spaces", []string{"default"}), ), }, + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minSupportedDescriptionVersion), + Config: testAccResourceSecurityRoleWithDescription(roleName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_security_role.test", "name", roleName), + resource.TestCheckNoResourceAttr("elasticstack_kibana_security_role.test", "kibana.0.feature.#"), + resource.TestCheckNoResourceAttr("elasticstack_kibana_security_role.test", "elasticsearch.0.indices.0.field_security.#"), + resource.TestCheckResourceAttr("elasticstack_kibana_security_role.test", "description", "Role description"), + ), + }, { SkipFunc: versionutils.CheckIfVersionIsUnsupported(minSupportedRemoteIndicesVersion), Config: testAccResourceSecurityRoleRemoteIndicesCreate(roleNameRemoteIndices), @@ -174,6 +185,32 @@ resource "elasticstack_kibana_security_role" "test" { `, roleName) } +func testAccResourceSecurityRoleWithDescription(roleName string) string { + return fmt.Sprintf(` +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_kibana_security_role" "test" { + name = "%s" + description = "Role description" + elasticsearch { + cluster = [ "create_snapshot" ] + indices { + names = ["sample"] + privileges = ["create", "read", "write"] + } + run_as = ["kibana", "elastic"] + } + kibana { + base = [ "all" ] + spaces = ["default"] + } +} + `, roleName) +} + func testAccResourceSecurityRoleRemoteIndicesCreate(roleName string) string { return fmt.Sprintf(` provider "elasticstack" { diff --git a/libs/go-kibana-rest/kbapi/api.kibana_role_management.go b/libs/go-kibana-rest/kbapi/api.kibana_role_management.go index 2451cb637..b3a557c1f 100644 --- a/libs/go-kibana-rest/kbapi/api.kibana_role_management.go +++ b/libs/go-kibana-rest/kbapi/api.kibana_role_management.go @@ -14,12 +14,13 @@ const ( // KibanaRole is the API role object type KibanaRole struct { - Name string `json:"name,omitempty"` - Metadata map[string]interface{} `json:"metadata,omitempty"` - TransientMedata *KibanaRoleTransientMetadata `json:"transient_metadata,omitempty"` - Elasticsearch *KibanaRoleElasticsearch `json:"elasticsearch,omitempty"` - Kibana []KibanaRoleKibana `json:"kibana,omitempty"` - CreateOnly bool `json:"-"` + Name string `json:"name,omitempty"` + Metadata map[string]interface{} `json:"metadata,omitempty"` + TransientMetadata *KibanaRoleTransientMetadata `json:"transient_metadata,omitempty"` + Elasticsearch *KibanaRoleElasticsearch `json:"elasticsearch,omitempty"` + Kibana []KibanaRoleKibana `json:"kibana,omitempty"` + Description string `json:"description,omitempty"` + CreateOnly bool `json:"-"` } // KibanaRoleTransientMetadata is the API TransientMedata object