Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ FLEET_CONTAINER_NAME=terraform-elasticstack-fleet
ACCEPTANCE_TESTS_CONTAINER_NAME=terraform-elasticstack-acceptance-tests
TOKEN_ACCEPTANCE_TESTS_CONTAINER_NAME=terraform-elasticstack-token-acceptance-tests
GOVERSION=1.25.1
TF_ELASTICSTACK_INCLUDE_EXPERIMENTAL=true
2 changes: 1 addition & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
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.

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.
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).

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.

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ jobs:
ELASTIC_PASSWORD: password
KIBANA_SYSTEM_USERNAME: kibana_system
KIBANA_SYSTEM_PASSWORD: password
TF_ELASTICSTACK_INCLUDE_EXPERIMENTAL: true
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:${{ matrix.version }}
Expand Down
1 change: 1 addition & 0 deletions CODING_STANDARDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ This document outlines the coding standards and conventions used in the terrafor
- Prefer using existing util functions over longer form, duplicated code:
- `utils.IsKnown(val)` instead of `!val.IsNull() && !val.IsUnknown()`
- `utils.ListTypeAs` instead of `val.ElementsAs` or similar for other collection types
- 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.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copilot kept suggesting that I use the create / update response instead of doing a secondary read. Adding this seems to help with that.


## Schema Definitions

Expand Down
3 changes: 2 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ services:
ELASTICSEARCH_USERNAME: elastic
ELASTICSEARCH_PASSWORD: ${ELASTICSEARCH_PASSWORD}
TF_LOG: ${TF_LOG:-info}
command: make testacc TESTARGS=${TESTARGS:-}
TF_ELASTICSTACK_INCLUDE_EXPERIMENTAL: "true"
command: make testacc TESTARGS='${TESTARGS:-}'

token-acceptance-tests:
profiles: ["token-acceptance-tests"]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
resource "elasticstack_kibana_security_list" "ip_list" {
space_id = "default"
name = "Trusted IP Addresses"
description = "List of trusted IP addresses for security rules"
type = "ip"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
resource "elasticstack_kibana_security_list" "keyword_list" {
space_id = "security"
list_id = "custom-keywords"
name = "Custom Keywords"
description = "Custom keyword list for detection rules"
type = "keyword"
}
9,211 changes: 4,679 additions & 4,532 deletions generated/kbapi/kibana.gen.go

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions generated/kbapi/transform_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,11 @@ func transformKibanaPaths(schema *Schema) {
"/api/actions/connector/{id}",
"/api/actions/connectors",
"/api/detection_engine/rules",
"/api/exception_lists",
"/api/exception_lists/items",
"/api/lists",
"/api/lists/index",
"/api/lists/items",
}

// Add a spaceId parameter if not already present
Expand Down
154 changes: 154 additions & 0 deletions internal/clients/kibana_oapi/security_lists.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package kibana_oapi

import (
"context"
"net/http"

"github.com/elastic/terraform-provider-elasticstack/generated/kbapi"
"github.com/elastic/terraform-provider-elasticstack/internal/diagutil"
"github.com/hashicorp/terraform-plugin-framework/diag"
)

// CreateListIndex creates the .lists and .items data streams for a space if they don't exist.
// This is required before any list operations can be performed.
func CreateListIndex(ctx context.Context, client *Client, spaceId string) diag.Diagnostics {
resp, err := client.API.CreateListIndexWithResponse(ctx, kbapi.SpaceId(spaceId))
if err != nil {
return diagutil.FrameworkDiagFromError(err)
}

switch resp.StatusCode() {
case http.StatusOK:
return nil
default:
return reportUnknownError(resp.StatusCode(), resp.Body)
}
}

// GetList reads a security list from the API by ID
func GetList(ctx context.Context, client *Client, spaceId string, params *kbapi.ReadListParams) (*kbapi.ReadListResponse, diag.Diagnostics) {
resp, err := client.API.ReadListWithResponse(ctx, kbapi.SpaceId(spaceId), params)
if err != nil {
return nil, diagutil.FrameworkDiagFromError(err)
}

switch resp.StatusCode() {
case http.StatusOK:
return resp, nil
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
return resp, nil
return resp.JSON200, nil

Does it make sense to return the parsed response models from these helpers?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it does. I may opt to do that refactor in the list item PR though for the sake of easily pulling these changes into that dependent PR.

case http.StatusNotFound:
return nil, nil
default:
return nil, reportUnknownError(resp.StatusCode(), resp.Body)
}
}

// CreateList creates a new security list.
func CreateList(ctx context.Context, client *Client, spaceId string, body kbapi.CreateListJSONRequestBody) (*kbapi.CreateListResponse, diag.Diagnostics) {
resp, err := client.API.CreateListWithResponse(ctx, kbapi.SpaceId(spaceId), body)
if err != nil {
return nil, diagutil.FrameworkDiagFromError(err)
}

switch resp.StatusCode() {
case http.StatusOK:
return resp, nil
default:
return nil, reportUnknownError(resp.StatusCode(), resp.Body)
}
}

// UpdateList updates an existing security list.
func UpdateList(ctx context.Context, client *Client, spaceId string, body kbapi.UpdateListJSONRequestBody) (*kbapi.UpdateListResponse, diag.Diagnostics) {
resp, err := client.API.UpdateListWithResponse(ctx, kbapi.SpaceId(spaceId), body)
if err != nil {
return nil, diagutil.FrameworkDiagFromError(err)
}

switch resp.StatusCode() {
case http.StatusOK:
return resp, nil
default:
return nil, reportUnknownError(resp.StatusCode(), resp.Body)
}
}

// DeleteList deletes an existing security list.
func DeleteList(ctx context.Context, client *Client, spaceId string, params *kbapi.DeleteListParams) diag.Diagnostics {
resp, err := client.API.DeleteListWithResponse(ctx, kbapi.SpaceId(spaceId), params)
if err != nil {
return diagutil.FrameworkDiagFromError(err)
}

switch resp.StatusCode() {
case http.StatusOK:
return nil
case http.StatusNotFound:
return nil
default:
return reportUnknownError(resp.StatusCode(), resp.Body)
}
}

// GetListItem reads a security list item from the API by ID or list_id and value
func GetListItem(ctx context.Context, client *Client, spaceId string, params *kbapi.ReadListItemParams) (*kbapi.ReadListItemResponse, diag.Diagnostics) {
resp, err := client.API.ReadListItemWithResponse(ctx, kbapi.SpaceId(spaceId), params)
if err != nil {
return nil, diagutil.FrameworkDiagFromError(err)
}

switch resp.StatusCode() {
case http.StatusOK:
return resp, nil
case http.StatusNotFound:
return nil, nil
default:
return nil, reportUnknownError(resp.StatusCode(), resp.Body)
}
}

// CreateListItem creates a new security list item.
func CreateListItem(ctx context.Context, client *Client, spaceId string, body kbapi.CreateListItemJSONRequestBody) (*kbapi.CreateListItemResponse, diag.Diagnostics) {
resp, err := client.API.CreateListItemWithResponse(ctx, kbapi.SpaceId(spaceId), body)
if err != nil {
return nil, diagutil.FrameworkDiagFromError(err)
}

switch resp.StatusCode() {
case http.StatusOK:
return resp, nil
default:
return nil, reportUnknownError(resp.StatusCode(), resp.Body)
}
}

// UpdateListItem updates an existing security list item.
func UpdateListItem(ctx context.Context, client *Client, spaceId string, body kbapi.UpdateListItemJSONRequestBody) (*kbapi.UpdateListItemResponse, diag.Diagnostics) {
resp, err := client.API.UpdateListItemWithResponse(ctx, kbapi.SpaceId(spaceId), body)
if err != nil {
return nil, diagutil.FrameworkDiagFromError(err)
}

switch resp.StatusCode() {
case http.StatusOK:
return resp, nil
default:
return nil, reportUnknownError(resp.StatusCode(), resp.Body)
}
}

// DeleteListItem deletes an existing security list item.
func DeleteListItem(ctx context.Context, client *Client, spaceId string, params *kbapi.DeleteListItemParams) diag.Diagnostics {
resp, err := client.API.DeleteListItemWithResponse(ctx, kbapi.SpaceId(spaceId), params)
if err != nil {
return diagutil.FrameworkDiagFromError(err)
}

switch resp.StatusCode() {
case http.StatusOK:
return nil
case http.StatusNotFound:
return nil
default:
return reportUnknownError(resp.StatusCode(), resp.Body)
}
}
Loading