Skip to content

Commit 0570ebd

Browse files
authored
Add security list resource (#1489)
* Add security list resource * Add security list resource * Update generated client * Add experimental flag to .env * Add directions about re-reading state to coding standards * Copilot PR feedback * Use normalized type for meta * Update coding standards guidance for utilities * Add link to docs * Use new helpers for type casting * Add errors for missing values on reads * Use composite id for internal id * Add import test * Remove nil checks for StringishPointerValue
1 parent 586ff66 commit 0570ebd

File tree

28 files changed

+5830
-4535
lines changed

28 files changed

+5830
-4535
lines changed

.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ FLEET_CONTAINER_NAME=terraform-elasticstack-fleet
1515
ACCEPTANCE_TESTS_CONTAINER_NAME=terraform-elasticstack-acceptance-tests
1616
TOKEN_ACCEPTANCE_TESTS_CONTAINER_NAME=terraform-elasticstack-token-acceptance-tests
1717
GOVERSION=1.25.1
18+
TF_ELASTICSTACK_INCLUDE_EXPERIMENTAL=true

.github/copilot-instructions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
You will be writing or reviewing code for the Terraform provider for Elastic Stack (Elasticsearch, Kibana, Fleet, APM, and Logstash). This is a Go-based repository hosting the provider source.
22

3-
When writing code, you must adhere to the coding standards and conventions outlined in the [CODING_STANDARDS.md](../CODING_STANDARDS.md) document in this repository.
3+
When writing code, you must adhere to the coding standards and conventions outlined in the [CODING_STANDARDS.md](../CODING_STANDARDS.md) document in this repository. After completing any code changes check again that they conform to the [CODING_STANDARDS.md](../CODING_STANDARDS.md).
44

55
When reviewing code, ensure that all changes comply with the coding standards and conventions specified in the [CODING_STANDARDS.md](../CODING_STANDARDS.md) document. Pay special attention to project structure, schema definitions, JSON handling, resource implementation, and testing practices.
66

.github/workflows/test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ jobs:
5555
ELASTIC_PASSWORD: password
5656
KIBANA_SYSTEM_USERNAME: kibana_system
5757
KIBANA_SYSTEM_PASSWORD: password
58+
TF_ELASTICSTACK_INCLUDE_EXPERIMENTAL: true
5859
services:
5960
elasticsearch:
6061
image: docker.elastic.co/elasticsearch/elasticsearch:${{ matrix.version }}

CODING_STANDARDS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ This document outlines the coding standards and conventions used in the terrafor
3636
- Prefer using existing util functions over longer form, duplicated code:
3737
- `utils.IsKnown(val)` instead of `!val.IsNull() && !val.IsUnknown()`
3838
- `utils.ListTypeAs` instead of `val.ElementsAs` or similar for other collection types
39+
- The final state for a resource should be derived from a read request following a mutative request (eg create or update). We should not use the response from a mutative request to build the final resource state.
3940

4041
## Schema Definitions
4142

docker-compose.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,8 @@ services:
134134
ELASTICSEARCH_USERNAME: elastic
135135
ELASTICSEARCH_PASSWORD: ${ELASTICSEARCH_PASSWORD}
136136
TF_LOG: ${TF_LOG:-info}
137-
command: make testacc TESTARGS=${TESTARGS:-}
137+
TF_ELASTICSTACK_INCLUDE_EXPERIMENTAL: "true"
138+
command: make testacc TESTARGS='${TESTARGS:-}'
138139

139140
token-acceptance-tests:
140141
profiles: ["token-acceptance-tests"]
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
resource "elasticstack_kibana_security_list" "ip_list" {
2+
space_id = "default"
3+
name = "Trusted IP Addresses"
4+
description = "List of trusted IP addresses for security rules"
5+
type = "ip"
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
resource "elasticstack_kibana_security_list" "keyword_list" {
2+
space_id = "security"
3+
list_id = "custom-keywords"
4+
name = "Custom Keywords"
5+
description = "Custom keyword list for detection rules"
6+
type = "keyword"
7+
}

generated/kbapi/kibana.gen.go

Lines changed: 4679 additions & 4532 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

generated/kbapi/transform_schema.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,11 @@ func transformKibanaPaths(schema *Schema) {
692692
"/api/actions/connector/{id}",
693693
"/api/actions/connectors",
694694
"/api/detection_engine/rules",
695+
"/api/exception_lists",
696+
"/api/exception_lists/items",
697+
"/api/lists",
698+
"/api/lists/index",
699+
"/api/lists/items",
695700
}
696701

697702
// Add a spaceId parameter if not already present
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package kibana_oapi
2+
3+
import (
4+
"context"
5+
"net/http"
6+
7+
"github.com/elastic/terraform-provider-elasticstack/generated/kbapi"
8+
"github.com/elastic/terraform-provider-elasticstack/internal/diagutil"
9+
"github.com/hashicorp/terraform-plugin-framework/diag"
10+
)
11+
12+
// CreateListIndex creates the .lists and .items data streams for a space if they don't exist.
13+
// This is required before any list operations can be performed.
14+
func CreateListIndex(ctx context.Context, client *Client, spaceId string) diag.Diagnostics {
15+
resp, err := client.API.CreateListIndexWithResponse(ctx, kbapi.SpaceId(spaceId))
16+
if err != nil {
17+
return diagutil.FrameworkDiagFromError(err)
18+
}
19+
20+
switch resp.StatusCode() {
21+
case http.StatusOK:
22+
return nil
23+
default:
24+
return reportUnknownError(resp.StatusCode(), resp.Body)
25+
}
26+
}
27+
28+
// GetList reads a security list from the API by ID
29+
func GetList(ctx context.Context, client *Client, spaceId string, params *kbapi.ReadListParams) (*kbapi.ReadListResponse, diag.Diagnostics) {
30+
resp, err := client.API.ReadListWithResponse(ctx, kbapi.SpaceId(spaceId), params)
31+
if err != nil {
32+
return nil, diagutil.FrameworkDiagFromError(err)
33+
}
34+
35+
switch resp.StatusCode() {
36+
case http.StatusOK:
37+
return resp, nil
38+
case http.StatusNotFound:
39+
return nil, nil
40+
default:
41+
return nil, reportUnknownError(resp.StatusCode(), resp.Body)
42+
}
43+
}
44+
45+
// CreateList creates a new security list.
46+
func CreateList(ctx context.Context, client *Client, spaceId string, body kbapi.CreateListJSONRequestBody) (*kbapi.CreateListResponse, diag.Diagnostics) {
47+
resp, err := client.API.CreateListWithResponse(ctx, kbapi.SpaceId(spaceId), body)
48+
if err != nil {
49+
return nil, diagutil.FrameworkDiagFromError(err)
50+
}
51+
52+
switch resp.StatusCode() {
53+
case http.StatusOK:
54+
return resp, nil
55+
default:
56+
return nil, reportUnknownError(resp.StatusCode(), resp.Body)
57+
}
58+
}
59+
60+
// UpdateList updates an existing security list.
61+
func UpdateList(ctx context.Context, client *Client, spaceId string, body kbapi.UpdateListJSONRequestBody) (*kbapi.UpdateListResponse, diag.Diagnostics) {
62+
resp, err := client.API.UpdateListWithResponse(ctx, kbapi.SpaceId(spaceId), body)
63+
if err != nil {
64+
return nil, diagutil.FrameworkDiagFromError(err)
65+
}
66+
67+
switch resp.StatusCode() {
68+
case http.StatusOK:
69+
return resp, nil
70+
default:
71+
return nil, reportUnknownError(resp.StatusCode(), resp.Body)
72+
}
73+
}
74+
75+
// DeleteList deletes an existing security list.
76+
func DeleteList(ctx context.Context, client *Client, spaceId string, params *kbapi.DeleteListParams) diag.Diagnostics {
77+
resp, err := client.API.DeleteListWithResponse(ctx, kbapi.SpaceId(spaceId), params)
78+
if err != nil {
79+
return diagutil.FrameworkDiagFromError(err)
80+
}
81+
82+
switch resp.StatusCode() {
83+
case http.StatusOK:
84+
return nil
85+
case http.StatusNotFound:
86+
return nil
87+
default:
88+
return reportUnknownError(resp.StatusCode(), resp.Body)
89+
}
90+
}
91+
92+
// GetListItem reads a security list item from the API by ID or list_id and value
93+
func GetListItem(ctx context.Context, client *Client, spaceId string, params *kbapi.ReadListItemParams) (*kbapi.ReadListItemResponse, diag.Diagnostics) {
94+
resp, err := client.API.ReadListItemWithResponse(ctx, kbapi.SpaceId(spaceId), params)
95+
if err != nil {
96+
return nil, diagutil.FrameworkDiagFromError(err)
97+
}
98+
99+
switch resp.StatusCode() {
100+
case http.StatusOK:
101+
return resp, nil
102+
case http.StatusNotFound:
103+
return nil, nil
104+
default:
105+
return nil, reportUnknownError(resp.StatusCode(), resp.Body)
106+
}
107+
}
108+
109+
// CreateListItem creates a new security list item.
110+
func CreateListItem(ctx context.Context, client *Client, spaceId string, body kbapi.CreateListItemJSONRequestBody) (*kbapi.CreateListItemResponse, diag.Diagnostics) {
111+
resp, err := client.API.CreateListItemWithResponse(ctx, kbapi.SpaceId(spaceId), body)
112+
if err != nil {
113+
return nil, diagutil.FrameworkDiagFromError(err)
114+
}
115+
116+
switch resp.StatusCode() {
117+
case http.StatusOK:
118+
return resp, nil
119+
default:
120+
return nil, reportUnknownError(resp.StatusCode(), resp.Body)
121+
}
122+
}
123+
124+
// UpdateListItem updates an existing security list item.
125+
func UpdateListItem(ctx context.Context, client *Client, spaceId string, body kbapi.UpdateListItemJSONRequestBody) (*kbapi.UpdateListItemResponse, diag.Diagnostics) {
126+
resp, err := client.API.UpdateListItemWithResponse(ctx, kbapi.SpaceId(spaceId), body)
127+
if err != nil {
128+
return nil, diagutil.FrameworkDiagFromError(err)
129+
}
130+
131+
switch resp.StatusCode() {
132+
case http.StatusOK:
133+
return resp, nil
134+
default:
135+
return nil, reportUnknownError(resp.StatusCode(), resp.Body)
136+
}
137+
}
138+
139+
// DeleteListItem deletes an existing security list item.
140+
func DeleteListItem(ctx context.Context, client *Client, spaceId string, params *kbapi.DeleteListItemParams) diag.Diagnostics {
141+
resp, err := client.API.DeleteListItemWithResponse(ctx, kbapi.SpaceId(spaceId), params)
142+
if err != nil {
143+
return diagutil.FrameworkDiagFromError(err)
144+
}
145+
146+
switch resp.StatusCode() {
147+
case http.StatusOK:
148+
return nil
149+
case http.StatusNotFound:
150+
return nil
151+
default:
152+
return reportUnknownError(resp.StatusCode(), resp.Body)
153+
}
154+
}

0 commit comments

Comments
 (0)