Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- Prevent a provider panic when the repository referenced in an `elasticstack_elasticsearch_snapshot_repository` does not exist ([#758](https://github.com/elastic/terraform-provider-elasticstack/pull/758))
- Add support for `remote_indicies` to `elasticstack_elasticsearch_security_api_key` (#766)[https://github.com/elastic/terraform-provider-elasticstack/pull/766]
- Add support for `icmp` and `browser` monitor types to `elasticstack_kibana_synthetics_monitor` resource (#772)[https://github.com/elastic/terraform-provider-elasticstack/pull/772]
- Migrate `elasticstack_fleet_enrollment_tokens` to terraform-plugin-framework ([#778](https://github.com/elastic/terraform-provider-elasticstack/pull/778))

## [0.11.6] - 2024-08-20

Expand Down
16 changes: 8 additions & 8 deletions docs/data-sources/fleet_enrollment_tokens.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,17 @@ data "elasticstack_fleet_enrollment_tokens" "test" {
### Read-Only

- `id` (String) The ID of this resource.
- `tokens` (List of Object) A list of enrollment tokens. (see [below for nested schema](#nestedatt--tokens))
- `tokens` (Attributes List) A list of enrollment tokens. (see [below for nested schema](#nestedatt--tokens))

<a id="nestedatt--tokens"></a>
### Nested Schema for `tokens`

Read-Only:

- `active` (Boolean)
- `api_key` (String)
- `api_key_id` (String)
- `created_at` (String)
- `key_id` (String)
- `name` (String)
- `policy_id` (String)
- `active` (Boolean) Indicates if the enrollment token is active.
- `api_key` (String, Sensitive) The API key.
- `api_key_id` (String) The API key identifier.
- `created_at` (String) The time at which the enrollment token was created.
- `key_id` (String) The unique identifier of the enrollment token.
- `name` (String) The name of the enrollment token.
- `policy_id` (String) The identifier of the associated agent policy.
6 changes: 6 additions & 0 deletions internal/clients/api_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,12 @@ func ConvertProviderData(providerData any) (*ApiClient, fwdiags.Diagnostics) {

return nil, diags
}
if client == nil {
diags.AddError(
"Unconfigured Client",
"Expected configured client. Please report this issue to the provider developers.",
)
}
return client, diags
}

Expand Down
32 changes: 26 additions & 6 deletions internal/clients/fleet/fleet.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net/http"

fleetapi "github.com/elastic/terraform-provider-elasticstack/generated/fleet"
fwdiag "github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
)

Expand All @@ -16,20 +17,20 @@ var (
)

// AllEnrollmentTokens reads all enrollment tokens from the API.
func AllEnrollmentTokens(ctx context.Context, client *Client) ([]fleetapi.EnrollmentApiKey, diag.Diagnostics) {
func AllEnrollmentTokens(ctx context.Context, client *Client) ([]fleetapi.EnrollmentApiKey, fwdiag.Diagnostics) {
resp, err := client.API.GetEnrollmentApiKeysWithResponse(ctx)
if err != nil {
return nil, diag.FromErr(err)
return nil, fromErr(err)
}

if resp.StatusCode() == http.StatusOK {
return resp.JSON200.Items, nil
}
return nil, reportUnknownError(resp.StatusCode(), resp.Body)
return nil, reportUnknownErrorFw(resp.StatusCode(), resp.Body)
}

// GetEnrollmentTokensByPolicy Get enrollment tokens by given policy ID
func GetEnrollmentTokensByPolicy(ctx context.Context, client *Client, policyID string) ([]fleetapi.EnrollmentApiKey, diag.Diagnostics) {
func GetEnrollmentTokensByPolicy(ctx context.Context, client *Client, policyID string) ([]fleetapi.EnrollmentApiKey, fwdiag.Diagnostics) {
resp, err := client.API.GetEnrollmentApiKeysWithResponse(ctx, func(ctx context.Context, req *http.Request) error {
q := req.URL.Query()
q.Set("kuery", "policy_id:"+policyID)
Expand All @@ -38,13 +39,13 @@ func GetEnrollmentTokensByPolicy(ctx context.Context, client *Client, policyID s
return nil
})
if err != nil {
return nil, diag.FromErr(err)
return nil, fromErr(err)
}

if resp.StatusCode() == http.StatusOK {
return resp.JSON200.Items, nil
}
return nil, reportUnknownError(resp.StatusCode(), resp.Body)
return nil, reportUnknownErrorFw(resp.StatusCode(), resp.Body)
}

// ReadAgentPolicy reads a specific agent policy from the API.
Expand Down Expand Up @@ -416,6 +417,16 @@ func AllPackages(ctx context.Context, client *Client, prerelease bool) ([]fleeta
}
}

// fromErr recreates the sdkdiag.FromErr functionality.
func fromErr(err error) fwdiag.Diagnostics {
if err == nil {
return nil
}
return fwdiag.Diagnostics{
fwdiag.NewErrorDiagnostic(err.Error(), ""),
}
}

func reportUnknownError(statusCode int, body []byte) diag.Diagnostics {
return diag.Diagnostics{
diag.Diagnostic{
Expand All @@ -425,3 +436,12 @@ func reportUnknownError(statusCode int, body []byte) diag.Diagnostics {
},
}
}

func reportUnknownErrorFw(statusCode int, body []byte) fwdiag.Diagnostics {
return fwdiag.Diagnostics{
fwdiag.NewErrorDiagnostic(
fmt.Sprintf("Unexpected status code from server: got HTTP %d", statusCode),
string(body),
),
}
}
4 changes: 0 additions & 4 deletions internal/elasticsearch/index/index/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ import (
var includeTypeNameMinUnsupportedVersion = version.Must(version.NewVersion("8.0.0"))

func (r Resource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
if !r.resourceReady(&resp.Diagnostics) {
return
}

var planModel tfModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...)
if resp.Diagnostics.HasError() {
Expand Down
4 changes: 0 additions & 4 deletions internal/elasticsearch/index/index/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ import (
)

func (r *Resource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
if !r.resourceReady(&resp.Diagnostics) {
return
}

var model tfModel
resp.Diagnostics.Append(req.State.Get(ctx, &model)...)
if resp.Diagnostics.HasError() {
Expand Down
4 changes: 0 additions & 4 deletions internal/elasticsearch/index/index/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ import (
)

func (r *Resource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
if !r.resourceReady(&resp.Diagnostics) {
return
}

var stateModel tfModel
resp.Diagnostics.Append(req.State.Get(ctx, &stateModel)...)
if resp.Diagnostics.HasError() {
Expand Down
13 changes: 0 additions & 13 deletions internal/elasticsearch/index/index/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"

"github.com/elastic/terraform-provider-elasticstack/internal/clients"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
)
Expand All @@ -18,18 +17,6 @@ type Resource struct {
client *clients.ApiClient
}

func (r *Resource) resourceReady(dg *diag.Diagnostics) bool {
if r.client == nil {
dg.AddError(
"Unconfigured Client",
"Expected configured client. Please report this issue to the provider developers.",
)

return false
}
return true
}

func (r *Resource) Configure(ctx context.Context, request resource.ConfigureRequest, response *resource.ConfigureResponse) {
client, diags := clients.ConvertProviderData(request.ProviderData)
response.Diagnostics.Append(diags...)
Expand Down
4 changes: 0 additions & 4 deletions internal/elasticsearch/index/index/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ import (
)

func (r *Resource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
if !r.resourceReady(&resp.Diagnostics) {
return
}

var planModel tfModel
var stateModel tfModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...)
Expand Down
33 changes: 33 additions & 0 deletions internal/fleet/enrollment_tokens/data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package enrollment_tokens

import (
"context"
"fmt"

"github.com/elastic/terraform-provider-elasticstack/internal/clients"
"github.com/hashicorp/terraform-plugin-framework/datasource"
)

var (
_ datasource.DataSource = &enrollmentTokensDataSource{}
_ datasource.DataSourceWithConfigure = &enrollmentTokensDataSource{}
)

// NewDataSource is a helper function to simplify the provider implementation.
func NewDataSource() datasource.DataSource {
return &enrollmentTokensDataSource{}
}

type enrollmentTokensDataSource struct {
client *clients.ApiClient
}

func (d *enrollmentTokensDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = fmt.Sprintf("%s_%s", req.ProviderTypeName, "fleet_enrollment_tokens")
}

func (d *enrollmentTokensDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
client, diags := clients.ConvertProviderData(req.ProviderData)
resp.Diagnostics.Append(diags...)
d.client = client
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package fleet_test
package enrollment_tokens_test

import (
"context"
"fmt"
"testing"

"github.com/elastic/terraform-provider-elasticstack/internal/acctest"
"github.com/elastic/terraform-provider-elasticstack/internal/clients"
"github.com/elastic/terraform-provider-elasticstack/internal/clients/fleet"
"github.com/elastic/terraform-provider-elasticstack/internal/utils"
"github.com/elastic/terraform-provider-elasticstack/internal/versionutils"
"github.com/hashicorp/go-version"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

var minVersionEnrollmentTokens = version.Must(version.NewVersion("8.6.0"))
Expand Down Expand Up @@ -46,3 +52,29 @@ data "elasticstack_fleet_enrollment_tokens" "test" {
policy_id = elasticstack_fleet_agent_policy.test.policy_id
}
`

func checkResourceAgentPolicyDestroy(s *terraform.State) error {
client, err := clients.NewAcceptanceTestingClient()
if err != nil {
return err
}

for _, rs := range s.RootModule().Resources {
if rs.Type != "elasticstack_fleet_agent_policy" {
continue
}

fleetClient, err := client.GetFleetClient()
if err != nil {
return err
}
policy, diags := fleet.ReadAgentPolicy(context.Background(), fleetClient, rs.Primary.ID)
if diags.HasError() {
return utils.SdkDiagsAsError(diags)
}
if policy != nil {
return fmt.Errorf("agent policy id=%v still exists, but it should have been removed", rs.Primary.ID)
}
}
return nil
}
44 changes: 44 additions & 0 deletions internal/fleet/enrollment_tokens/models.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package enrollment_tokens

import (
"context"

fleetapi "github.com/elastic/terraform-provider-elasticstack/generated/fleet"
"github.com/elastic/terraform-provider-elasticstack/internal/utils"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/types"
)

type enrollmentTokensModel struct {
ID types.String `tfsdk:"id"`
PolicyID types.String `tfsdk:"policy_id"`
Tokens types.List `tfsdk:"tokens"` //> enrollmentTokenModel
}

type enrollmentTokenModel struct {
KeyID types.String `tfsdk:"key_id"`
ApiKey types.String `tfsdk:"api_key"`
ApiKeyID types.String `tfsdk:"api_key_id"`
CreatedAt types.String `tfsdk:"created_at"`
Name types.String `tfsdk:"name"`
Active types.Bool `tfsdk:"active"`
PolicyID types.String `tfsdk:"policy_id"`
}

func (model *enrollmentTokensModel) populateFromAPI(ctx context.Context, data []fleetapi.EnrollmentApiKey) (diags diag.Diagnostics) {
model.Tokens = utils.SliceToListType(ctx, data, getTokenType(), path.Root("tokens"), diags, newEnrollmentTokenModel)
return
}

func newEnrollmentTokenModel(data fleetapi.EnrollmentApiKey) enrollmentTokenModel {
return enrollmentTokenModel{
KeyID: types.StringValue(data.Id),
Active: types.BoolValue(data.Active),
ApiKey: types.StringValue(data.ApiKey),
ApiKeyID: types.StringValue(data.ApiKeyId),
CreatedAt: types.StringValue(data.CreatedAt),
Name: types.StringPointerValue(data.Name),
PolicyID: types.StringPointerValue(data.PolicyId),
}
}
59 changes: 59 additions & 0 deletions internal/fleet/enrollment_tokens/read.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package enrollment_tokens

import (
"context"

fleetapi "github.com/elastic/terraform-provider-elasticstack/generated/fleet"
"github.com/elastic/terraform-provider-elasticstack/internal/clients/fleet"
"github.com/elastic/terraform-provider-elasticstack/internal/utils"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/types"
)

func (d *enrollmentTokensDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var model enrollmentTokensModel

diags := req.Config.Get(ctx, &model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

client, err := d.client.GetFleetClient()
if err != nil {
resp.Diagnostics.AddError(err.Error(), "")
return
}

var tokens []fleetapi.EnrollmentApiKey
policyID := model.PolicyID.ValueString()
if policyID == "" {
tokens, diags = fleet.AllEnrollmentTokens(ctx, client)
} else {
tokens, diags = fleet.GetEnrollmentTokensByPolicy(ctx, client, policyID)
}
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

if policyID != "" {
model.ID = types.StringValue(policyID)
} else {
hash, err := utils.StringToHash(client.URL)
if err != nil {
resp.Diagnostics.AddError(err.Error(), "")
return
}
model.ID = types.StringPointerValue(hash)
}

diags = model.populateFromAPI(ctx, tokens)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

diags = resp.State.Set(ctx, model)
resp.Diagnostics.Append(diags...)
}
Loading