Skip to content

Commit 1a7e65e

Browse files
committed
Add security list item resource
1 parent 15e62bf commit 1a7e65e

File tree

11 files changed

+635
-0
lines changed

11 files changed

+635
-0
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package security_list_item_test
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/elastic/terraform-provider-elasticstack/internal/acctest"
8+
"github.com/elastic/terraform-provider-elasticstack/internal/clients"
9+
"github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi"
10+
"github.com/google/uuid"
11+
"github.com/hashicorp/terraform-plugin-testing/config"
12+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
13+
)
14+
15+
func ensureListIndexExists(t *testing.T) {
16+
client, err := clients.NewAcceptanceTestingClient()
17+
if err != nil {
18+
t.Fatalf("Failed to create client: %v", err)
19+
}
20+
21+
kibanaClient, err := client.GetKibanaOapiClient()
22+
if err != nil {
23+
t.Fatalf("Failed to get Kibana client: %v", err)
24+
}
25+
26+
diags := kibana_oapi.CreateListIndex(context.Background(), kibanaClient, "default")
27+
if diags.HasError() {
28+
// It's OK if it already exists, we'll only fail on other errors
29+
for _, d := range diags {
30+
if d.Summary() != "Unexpected status code from server: got HTTP 409" {
31+
t.Fatalf("Failed to create list index: %v", d.Detail())
32+
}
33+
}
34+
}
35+
}
36+
37+
func TestAccResourceSecurityListItem(t *testing.T) {
38+
listID := "test-list-items-" + uuid.New().String()
39+
resource.Test(t, resource.TestCase{
40+
PreCheck: func() {
41+
acctest.PreCheck(t)
42+
ensureListIndexExists(t)
43+
},
44+
ProtoV6ProviderFactories: acctest.Providers,
45+
Steps: []resource.TestStep{
46+
{ // Create
47+
ConfigDirectory: acctest.NamedTestCaseDirectory("create"),
48+
ConfigVariables: config.Variables{
49+
"list_id": config.StringVariable(listID),
50+
"value": config.StringVariable("test-value-1"),
51+
},
52+
Check: resource.ComposeTestCheckFunc(
53+
resource.TestCheckResourceAttrSet("elasticstack_kibana_security_list_item.test", "id"),
54+
resource.TestCheckResourceAttr("elasticstack_kibana_security_list_item.test", "value", "test-value-1"),
55+
resource.TestCheckResourceAttrSet("elasticstack_kibana_security_list_item.test", "created_at"),
56+
resource.TestCheckResourceAttrSet("elasticstack_kibana_security_list_item.test", "created_by"),
57+
resource.TestCheckResourceAttrSet("elasticstack_kibana_security_list_item.test", "updated_at"),
58+
resource.TestCheckResourceAttrSet("elasticstack_kibana_security_list_item.test", "updated_by"),
59+
),
60+
},
61+
{ // Update
62+
ConfigDirectory: acctest.NamedTestCaseDirectory("update"),
63+
ConfigVariables: config.Variables{
64+
"list_id": config.StringVariable(listID),
65+
"value": config.StringVariable("test-value-updated"),
66+
},
67+
Check: resource.ComposeTestCheckFunc(
68+
resource.TestCheckResourceAttr("elasticstack_kibana_security_list_item.test", "value", "test-value-updated"),
69+
),
70+
},
71+
},
72+
})
73+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package security_list_item
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
7+
"github.com/elastic/terraform-provider-elasticstack/generated/kbapi"
8+
"github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi"
9+
"github.com/hashicorp/terraform-plugin-framework/resource"
10+
)
11+
12+
func (r *securityListItemResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
13+
var plan SecurityListItemModel
14+
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
15+
if resp.Diagnostics.HasError() {
16+
return
17+
}
18+
19+
// Get Kibana client
20+
client, err := r.client.GetKibanaOapiClient()
21+
if err != nil {
22+
resp.Diagnostics.AddError("Failed to get Kibana client", err.Error())
23+
return
24+
}
25+
26+
// Convert plan to API request
27+
createReq, diags := plan.toAPICreateModel(ctx)
28+
resp.Diagnostics.Append(diags...)
29+
if resp.Diagnostics.HasError() {
30+
return
31+
}
32+
33+
// Create the list item
34+
createResp, diags := kibana_oapi.CreateListItem(ctx, client, plan.SpaceID.ValueString(), *createReq)
35+
resp.Diagnostics.Append(diags...)
36+
if resp.Diagnostics.HasError() {
37+
return
38+
}
39+
40+
if createResp == nil || createResp.JSON200 == nil {
41+
resp.Diagnostics.AddError("Failed to create security list item", "API returned empty response")
42+
return
43+
}
44+
45+
// Read the created list item to populate state
46+
id := kbapi.SecurityListsAPIListId(createResp.JSON200.Id)
47+
readParams := &kbapi.ReadListItemParams{
48+
Id: &id,
49+
}
50+
51+
readResp, diags := kibana_oapi.GetListItem(ctx, client, plan.SpaceID.ValueString(), readParams)
52+
resp.Diagnostics.Append(diags...)
53+
if resp.Diagnostics.HasError() {
54+
return
55+
}
56+
57+
if readResp == nil || readResp.JSON200 == nil {
58+
resp.State.RemoveResource(ctx)
59+
return
60+
}
61+
62+
// Unmarshal the response body to get the list item
63+
var listItem kbapi.SecurityListsAPIListItem
64+
if err := json.Unmarshal(readResp.Body, &listItem); err != nil {
65+
resp.Diagnostics.AddError("Failed to parse list item response", err.Error())
66+
return
67+
}
68+
69+
// Update state with read response
70+
diags = plan.fromAPIModel(ctx, &listItem)
71+
resp.Diagnostics.Append(diags...)
72+
if resp.Diagnostics.HasError() {
73+
return
74+
}
75+
76+
resp.Diagnostics.Append(resp.State.Set(ctx, plan)...)
77+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package security_list_item
2+
3+
import (
4+
"context"
5+
6+
"github.com/elastic/terraform-provider-elasticstack/generated/kbapi"
7+
"github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi"
8+
"github.com/hashicorp/terraform-plugin-framework/resource"
9+
)
10+
11+
func (r *securityListItemResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
12+
var state SecurityListItemModel
13+
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
14+
if resp.Diagnostics.HasError() {
15+
return
16+
}
17+
18+
// Get Kibana client
19+
client, err := r.client.GetKibanaOapiClient()
20+
if err != nil {
21+
resp.Diagnostics.AddError("Failed to get Kibana client", err.Error())
22+
return
23+
}
24+
25+
// Delete by ID
26+
id := kbapi.SecurityListsAPIListItemId(state.ID.ValueString())
27+
params := &kbapi.DeleteListItemParams{
28+
Id: &id,
29+
}
30+
31+
diags := kibana_oapi.DeleteListItem(ctx, client, state.SpaceID.ValueString(), params)
32+
resp.Diagnostics.Append(diags...)
33+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package security_list_item
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
7+
"github.com/elastic/terraform-provider-elasticstack/generated/kbapi"
8+
"github.com/hashicorp/terraform-plugin-framework/diag"
9+
"github.com/hashicorp/terraform-plugin-framework/types"
10+
)
11+
12+
type SecurityListItemModel struct {
13+
ID types.String `tfsdk:"id"`
14+
SpaceID types.String `tfsdk:"space_id"`
15+
ListID types.String `tfsdk:"list_id"`
16+
Value types.String `tfsdk:"value"`
17+
Meta types.String `tfsdk:"meta"`
18+
CreatedAt types.String `tfsdk:"created_at"`
19+
CreatedBy types.String `tfsdk:"created_by"`
20+
UpdatedAt types.String `tfsdk:"updated_at"`
21+
UpdatedBy types.String `tfsdk:"updated_by"`
22+
Version types.String `tfsdk:"version"`
23+
}
24+
25+
// toAPICreateModel converts the Terraform model to the API create request body
26+
func (m *SecurityListItemModel) toAPICreateModel(ctx context.Context) (*kbapi.CreateListItemJSONRequestBody, diag.Diagnostics) {
27+
var diags diag.Diagnostics
28+
29+
body := &kbapi.CreateListItemJSONRequestBody{
30+
ListId: kbapi.SecurityListsAPIListId(m.ListID.ValueString()),
31+
Value: kbapi.SecurityListsAPIListItemValue(m.Value.ValueString()),
32+
}
33+
34+
// Set optional ID if specified
35+
if !m.ID.IsNull() && !m.ID.IsUnknown() {
36+
id := kbapi.SecurityListsAPIListItemId(m.ID.ValueString())
37+
body.Id = &id
38+
}
39+
40+
// Set optional meta if specified
41+
if !m.Meta.IsNull() && !m.Meta.IsUnknown() {
42+
var meta kbapi.SecurityListsAPIListItemMetadata
43+
if err := json.Unmarshal([]byte(m.Meta.ValueString()), &meta); err != nil {
44+
diags.AddError("Failed to parse meta JSON", err.Error())
45+
return nil, diags
46+
}
47+
body.Meta = &meta
48+
}
49+
50+
return body, diags
51+
}
52+
53+
// toAPIUpdateModel converts the Terraform model to the API update request body
54+
func (m *SecurityListItemModel) toAPIUpdateModel(ctx context.Context) (*kbapi.UpdateListItemJSONRequestBody, diag.Diagnostics) {
55+
var diags diag.Diagnostics
56+
57+
body := &kbapi.UpdateListItemJSONRequestBody{
58+
Id: kbapi.SecurityListsAPIListItemId(m.ID.ValueString()),
59+
Value: kbapi.SecurityListsAPIListItemValue(m.Value.ValueString()),
60+
}
61+
62+
// Set optional version if available
63+
if !m.Version.IsNull() && !m.Version.IsUnknown() {
64+
version := kbapi.SecurityListsAPIListVersionId(m.Version.ValueString())
65+
body.UnderscoreVersion = &version
66+
}
67+
68+
// Set optional meta if specified
69+
if !m.Meta.IsNull() && !m.Meta.IsUnknown() {
70+
var meta kbapi.SecurityListsAPIListItemMetadata
71+
if err := json.Unmarshal([]byte(m.Meta.ValueString()), &meta); err != nil {
72+
diags.AddError("Failed to parse meta JSON", err.Error())
73+
return nil, diags
74+
}
75+
body.Meta = &meta
76+
}
77+
78+
return body, diags
79+
}
80+
81+
// fromAPIModel populates the Terraform model from an API response
82+
func (m *SecurityListItemModel) fromAPIModel(ctx context.Context, apiItem *kbapi.SecurityListsAPIListItem) diag.Diagnostics {
83+
var diags diag.Diagnostics
84+
85+
m.ID = types.StringValue(string(apiItem.Id))
86+
m.ListID = types.StringValue(string(apiItem.ListId))
87+
m.Value = types.StringValue(string(apiItem.Value))
88+
m.CreatedAt = types.StringValue(apiItem.CreatedAt.Format("2006-01-02T15:04:05.000Z"))
89+
m.CreatedBy = types.StringValue(apiItem.CreatedBy)
90+
m.UpdatedAt = types.StringValue(apiItem.UpdatedAt.Format("2006-01-02T15:04:05.000Z"))
91+
m.UpdatedBy = types.StringValue(apiItem.UpdatedBy)
92+
93+
// Set version if available
94+
if apiItem.UnderscoreVersion != nil {
95+
m.Version = types.StringValue(string(*apiItem.UnderscoreVersion))
96+
} else {
97+
m.Version = types.StringNull()
98+
}
99+
100+
// Set meta if available
101+
if apiItem.Meta != nil {
102+
metaJSON, err := json.Marshal(apiItem.Meta)
103+
if err != nil {
104+
diags.AddError("Failed to serialize meta", err.Error())
105+
return diags
106+
}
107+
m.Meta = types.StringValue(string(metaJSON))
108+
} else {
109+
m.Meta = types.StringNull()
110+
}
111+
112+
return diags
113+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package security_list_item
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
7+
"github.com/elastic/terraform-provider-elasticstack/generated/kbapi"
8+
"github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi"
9+
"github.com/hashicorp/terraform-plugin-framework/resource"
10+
)
11+
12+
func (r *securityListItemResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
13+
var state SecurityListItemModel
14+
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
15+
if resp.Diagnostics.HasError() {
16+
return
17+
}
18+
19+
// Get Kibana client
20+
client, err := r.client.GetKibanaOapiClient()
21+
if err != nil {
22+
resp.Diagnostics.AddError("Failed to get Kibana client", err.Error())
23+
return
24+
}
25+
26+
// Read by ID
27+
id := kbapi.SecurityListsAPIListId(state.ID.ValueString())
28+
params := &kbapi.ReadListItemParams{
29+
Id: &id,
30+
}
31+
32+
readResp, diags := kibana_oapi.GetListItem(ctx, client, state.SpaceID.ValueString(), params)
33+
resp.Diagnostics.Append(diags...)
34+
if resp.Diagnostics.HasError() {
35+
return
36+
}
37+
38+
if readResp == nil || readResp.JSON200 == nil {
39+
resp.State.RemoveResource(ctx)
40+
return
41+
}
42+
43+
// The response can be a single item or an array, so we need to unmarshal from the body
44+
// When querying by ID, we expect a single item
45+
var listItem kbapi.SecurityListsAPIListItem
46+
if err := json.Unmarshal(readResp.Body, &listItem); err != nil {
47+
resp.Diagnostics.AddError("Failed to parse list item response", err.Error())
48+
return
49+
}
50+
51+
// Update state with response
52+
diags = state.fromAPIModel(ctx, &listItem)
53+
resp.Diagnostics.Append(diags...)
54+
if resp.Diagnostics.HasError() {
55+
return
56+
}
57+
58+
resp.Diagnostics.Append(resp.State.Set(ctx, state)...)
59+
}

0 commit comments

Comments
 (0)