Skip to content

impl framework data_source.fleet_enrollment_tokens #778

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Sep 20, 2024
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 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
Loading