diff --git a/CHANGELOG.md b/CHANGELOG.md index a76a1374..12617303 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - Add `elasticstack_elasticsearch_watch` for managing Elasticsearch Watches ([#155](https://github.com/elastic/terraform-provider-elasticstack/pull/155)) - Add `elasticstack_kibana_alerting_rule` for managing Kibana alerting rules ([#292](https://github.com/elastic/terraform-provider-elasticstack/pull/292)) - Add client for communicating with the Fleet APIs ([#311](https://github.com/elastic/terraform-provider-elasticstack/pull/311)]) +- Add `elasticstack_fleet_enrollment_tokens` and `elasticstack_fleet_agent_policy` for managing Fleet enrollment tokens and agent policies ([#322](https://github.com/elastic/terraform-provider-elasticstack/pull/322)]) ### Fixed - Updated unsupported queue_max_bytes_number and queue_max_bytes_units with queue.max_bytes ([#266](https://github.com/elastic/terraform-provider-elasticstack/issues/266)) diff --git a/Makefile b/Makefile index 47f24aab..6a03fab2 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ SWAGGER_VERSION ?= 8.7 GOVERSION ?= 1.19 -STACK_VERSION ?= 8.0.0 +STACK_VERSION ?= 8.6.0 ELASTICSEARCH_NAME ?= terraform-elasticstack-es ELASTICSEARCH_ENDPOINTS ?= http://$(ELASTICSEARCH_NAME):9200 diff --git a/docs/data-sources/fleet_enrollment_tokens.md b/docs/data-sources/fleet_enrollment_tokens.md new file mode 100644 index 00000000..85678920 --- /dev/null +++ b/docs/data-sources/fleet_enrollment_tokens.md @@ -0,0 +1,48 @@ +--- +subcategory: "Fleet" +layout: "" +page_title: "Elasticstack: elasticstack_fleet_enrollment_tokens Data Source" +description: |- + Gets information about Fleet Enrollment Tokens. See https://www.elastic.co/guide/en/fleet/current/fleet-enrollment-tokens.html +--- + +# Data Source: elasticstack_fleet_enrollment_tokens + +This data source provides information about Fleet Enrollment Tokens. + +## Example Usage + +```terraform +provider "elasticstack" { + kibana {} +} + +data "elasticstack_fleet_enrollment_tokens" "test" { + policy_id = "223b1bf8-240f-463f-8466-5062670d0754" +} +``` + + +## Schema + +### Optional + +- `policy_id` (String) The identifier of the target agent policy. When provided, only the enrollment tokens associated with this agent policy will be selected. Omit this value to select all enrollment tokens. + +### 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)) + + +### 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) diff --git a/docs/resources/fleet_agent_policy.md b/docs/resources/fleet_agent_policy.md new file mode 100644 index 00000000..5a7039f8 --- /dev/null +++ b/docs/resources/fleet_agent_policy.md @@ -0,0 +1,60 @@ +--- +subcategory: "Fleet" +layout: "" +page_title: "Elasticstack: elasticstack_fleet_agent_policy Resource" +description: |- + Creates or updates a Fleet Agent Policy. +--- + +# Resource: elasticstack_fleet_agent_policy + +Creates or updates a Fleet Agent Policy. See https://www.elastic.co/guide/en/fleet/current/fleet-api-docs.html#create-agent-policy-api + +## Example Usage + +```terraform +provider "elasticstack" { + kibana {} +} + +resource "elasticstack_fleet_agent_policy" "test_policy" { + name = "Test Policy" + namespace = "default" + description = "Test Agent Policy" + sys_monitoring = true + monitor_logs = true + monitor_metrics = true +} +``` + + +## Schema + +### Required + +- `name` (String) The name of the agent policy. +- `namespace` (String) The namespace of the agent policy. + +### Optional + +- `data_output_id` (String) The identifier for the data output. +- `description` (String) The description of the agent policy. +- `download_source_id` (String) The identifier for the Elastic Agent binary download server. +- `fleet_server_host_id` (String) The identifier for the Fleet server host. +- `monitor_logs` (Boolean) Enable collection of agent logs. +- `monitor_metrics` (Boolean) Enable collection of agent metrics. +- `monitoring_output_id` (String) The identifier for monitoring output. +- `policy_id` (String) Unique identifier of the agent policy. +- `sys_monitoring` (Boolean) Enable collection of system logs and metrics. + +### Read-Only + +- `id` (String) The ID of this resource. + +## Import + +Import is supported using the following syntax: + +```shell +terraform import elasticstack_kibana_fleet_agent_policy.my_policy / +``` diff --git a/examples/data-sources/elasticstack_fleet_enrollment_tokens/data-source.tf b/examples/data-sources/elasticstack_fleet_enrollment_tokens/data-source.tf new file mode 100644 index 00000000..5604519c --- /dev/null +++ b/examples/data-sources/elasticstack_fleet_enrollment_tokens/data-source.tf @@ -0,0 +1,7 @@ +provider "elasticstack" { + kibana {} +} + +data "elasticstack_fleet_enrollment_tokens" "test" { + policy_id = "223b1bf8-240f-463f-8466-5062670d0754" +} diff --git a/examples/resources/elasticstack_fleet_agent_policy/import.sh b/examples/resources/elasticstack_fleet_agent_policy/import.sh new file mode 100644 index 00000000..7037f48d --- /dev/null +++ b/examples/resources/elasticstack_fleet_agent_policy/import.sh @@ -0,0 +1 @@ +terraform import elasticstack_kibana_fleet_agent_policy.my_policy / diff --git a/examples/resources/elasticstack_fleet_agent_policy/resource.tf b/examples/resources/elasticstack_fleet_agent_policy/resource.tf new file mode 100644 index 00000000..81625d7f --- /dev/null +++ b/examples/resources/elasticstack_fleet_agent_policy/resource.tf @@ -0,0 +1,12 @@ +provider "elasticstack" { + kibana {} +} + +resource "elasticstack_fleet_agent_policy" "test_policy" { + name = "Test Policy" + namespace = "default" + description = "Test Agent Policy" + sys_monitoring = true + monitor_logs = true + monitor_metrics = true +} diff --git a/go.mod b/go.mod index 5979b18e..96002a77 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/elastic/terraform-provider-elasticstack go 1.19 require ( + github.com/deepmap/oapi-codegen v1.12.4 github.com/disaster37/go-kibana-rest/v8 v8.5.0 github.com/elastic/go-elasticsearch/v7 v7.17.7 github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 @@ -16,12 +17,14 @@ require ( require ( github.com/agext/levenshtein v1.2.3 // indirect + github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/color v1.13.0 // indirect github.com/go-resty/resty/v2 v2.7.0 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/go-cmp v0.5.9 // indirect + github.com/google/uuid v1.3.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-checkpoint v0.5.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect diff --git a/go.sum b/go.sum index c71dad95..b1affb45 100644 --- a/go.sum +++ b/go.sum @@ -6,21 +6,27 @@ github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/ github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C67SkzkDfmQuVln04ygHj3vjZfd9FL+GmQQ= github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= +github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= +github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deepmap/oapi-codegen v1.12.4 h1:pPmn6qI9MuOtCz82WY2Xaw46EQjgvxednXXrP7g5Q2s= +github.com/deepmap/oapi-codegen v1.12.4/go.mod h1:3lgHGMu6myQ2vqbbTXH2H1o4eXFTGnFiDaOaKKl5yas= github.com/disaster37/go-kibana-rest/v8 v8.5.0 h1:Wr2CMopHj0wAh7kq3p355jXctISL1LdAZ9kYN/v6abw= github.com/disaster37/go-kibana-rest/v8 v8.5.0/go.mod h1:wVGm1b93CSmsHYoxzqhDszv347xr+fELdigS8XLO+bg= github.com/elastic/go-elasticsearch/v7 v7.17.7 h1:pcYNfITNPusl+cLwLN6OLmVT+F73Els0nbaWOmYachs= @@ -55,6 +61,8 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -110,6 +118,7 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -163,11 +172,13 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= diff --git a/internal/clients/fleet/fleet.go b/internal/clients/fleet/fleet.go new file mode 100644 index 00000000..0ed194b9 --- /dev/null +++ b/internal/clients/fleet/fleet.go @@ -0,0 +1,101 @@ +package fleet + +import ( + "context" + "fmt" + "net/http" + + "github.com/elastic/terraform-provider-elasticstack/internal/clients/fleet/fleetapi" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" +) + +// AllEnrollmentTokens reads all enrollment tokens from the API. +func AllEnrollmentTokens(ctx context.Context, client *Client) ([]fleetapi.EnrollmentApiKey, diag.Diagnostics) { + resp, err := client.API.GetEnrollmentApiKeysWithResponse(ctx) + if err != nil { + return nil, diag.FromErr(err) + } + + if resp.StatusCode() == http.StatusOK { + return resp.JSON200.Items, nil + } + return nil, reportUnknownError(resp.StatusCode(), resp.Body) +} + +// ReadAgentPolicy reads a specific agent policy from the API. +func ReadAgentPolicy(ctx context.Context, client *Client, id string) (*fleetapi.AgentPolicy, diag.Diagnostics) { + resp, err := client.API.AgentPolicyInfoWithResponse(ctx, id) + if err != nil { + return nil, diag.FromErr(err) + } + + switch resp.StatusCode() { + case http.StatusOK: + return &resp.JSON200.Item, nil + case http.StatusNotFound: + return nil, nil + default: + return nil, reportUnknownError(resp.StatusCode(), resp.Body) + } +} + +// CreateAgentPolicy creates a new agent policy. +func CreateAgentPolicy(ctx context.Context, client *Client, req fleetapi.AgentPolicyCreateRequest) (*fleetapi.AgentPolicy, diag.Diagnostics) { + resp, err := client.API.CreateAgentPolicyWithResponse(ctx, req) + if err != nil { + return nil, diag.FromErr(err) + } + + switch resp.StatusCode() { + case http.StatusOK: + return resp.JSON200.Item, nil + default: + return nil, reportUnknownError(resp.StatusCode(), resp.Body) + } +} + +// UpdateAgentPolicy updates an existing agent policy. +func UpdateAgentPolicy(ctx context.Context, client *Client, id string, req fleetapi.AgentPolicyUpdateRequest) (*fleetapi.AgentPolicy, diag.Diagnostics) { + resp, err := client.API.UpdateAgentPolicyWithResponse(ctx, id, req) + if err != nil { + return nil, diag.FromErr(err) + } + + switch resp.StatusCode() { + case http.StatusOK: + return &resp.JSON200.Item, nil + default: + return nil, reportUnknownError(resp.StatusCode(), resp.Body) + } +} + +// DeleteAgentPolicy deletes an existing agent policy +func DeleteAgentPolicy(ctx context.Context, client *Client, id string) diag.Diagnostics { + body := fleetapi.DeleteAgentPolicyJSONRequestBody{ + AgentPolicyId: id, + } + + resp, err := client.API.DeleteAgentPolicyWithResponse(ctx, body) + if err != nil { + return diag.FromErr(err) + } + + switch resp.StatusCode() { + case http.StatusOK: + return nil + case http.StatusNotFound: + return nil + default: + return reportUnknownError(resp.StatusCode(), resp.Body) + } +} + +func reportUnknownError(statusCode int, body []byte) diag.Diagnostics { + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Error, + Summary: fmt.Sprintf("Unexpected status code from server: got HTTP %d", statusCode), + Detail: string(body), + }, + } +} diff --git a/internal/clients/fleet/fleetapi/client_gen.go b/internal/clients/fleet/fleetapi/client_gen.go index 72c1f427..6e83a7a7 100644 --- a/internal/clients/fleet/fleetapi/client_gen.go +++ b/internal/clients/fleet/fleetapi/client_gen.go @@ -4,10 +4,16 @@ package fleetapi import ( + "bytes" "context" + "encoding/json" + "fmt" + "io" "net/http" "net/url" "strings" + + "github.com/deepmap/oapi-codegen/pkg/runtime" ) // RequestEditorFn is the function signature for the RequestEditor callback function @@ -83,6 +89,310 @@ func WithRequestEditorFn(fn RequestEditorFn) ClientOption { // The interface specification for the client above. type ClientInterface interface { + // CreateAgentPolicy request with any body + CreateAgentPolicyWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + CreateAgentPolicy(ctx context.Context, body CreateAgentPolicyJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // DeleteAgentPolicy request with any body + DeleteAgentPolicyWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + DeleteAgentPolicy(ctx context.Context, body DeleteAgentPolicyJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // AgentPolicyInfo request + AgentPolicyInfo(ctx context.Context, agentPolicyId string, reqEditors ...RequestEditorFn) (*http.Response, error) + + // UpdateAgentPolicy request with any body + UpdateAgentPolicyWithBody(ctx context.Context, agentPolicyId string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + UpdateAgentPolicy(ctx context.Context, agentPolicyId string, body UpdateAgentPolicyJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetEnrollmentApiKeys request + GetEnrollmentApiKeys(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) +} + +func (c *Client) CreateAgentPolicyWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewCreateAgentPolicyRequestWithBody(c.Server, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) CreateAgentPolicy(ctx context.Context, body CreateAgentPolicyJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewCreateAgentPolicyRequest(c.Server, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) DeleteAgentPolicyWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewDeleteAgentPolicyRequestWithBody(c.Server, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) DeleteAgentPolicy(ctx context.Context, body DeleteAgentPolicyJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewDeleteAgentPolicyRequest(c.Server, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) AgentPolicyInfo(ctx context.Context, agentPolicyId string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewAgentPolicyInfoRequest(c.Server, agentPolicyId) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) UpdateAgentPolicyWithBody(ctx context.Context, agentPolicyId string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewUpdateAgentPolicyRequestWithBody(c.Server, agentPolicyId, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) UpdateAgentPolicy(ctx context.Context, agentPolicyId string, body UpdateAgentPolicyJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewUpdateAgentPolicyRequest(c.Server, agentPolicyId, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetEnrollmentApiKeys(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetEnrollmentApiKeysRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +// NewCreateAgentPolicyRequest calls the generic CreateAgentPolicy builder with application/json body +func NewCreateAgentPolicyRequest(server string, body CreateAgentPolicyJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewCreateAgentPolicyRequestWithBody(server, "application/json", bodyReader) +} + +// NewCreateAgentPolicyRequestWithBody generates requests for CreateAgentPolicy with any type of body +func NewCreateAgentPolicyRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/agent_policies") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewDeleteAgentPolicyRequest calls the generic DeleteAgentPolicy builder with application/json body +func NewDeleteAgentPolicyRequest(server string, body DeleteAgentPolicyJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewDeleteAgentPolicyRequestWithBody(server, "application/json", bodyReader) +} + +// NewDeleteAgentPolicyRequestWithBody generates requests for DeleteAgentPolicy with any type of body +func NewDeleteAgentPolicyRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/agent_policies/delete") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewAgentPolicyInfoRequest generates requests for AgentPolicyInfo +func NewAgentPolicyInfoRequest(server string, agentPolicyId string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "agentPolicyId", runtime.ParamLocationPath, agentPolicyId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/agent_policies/%s", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewUpdateAgentPolicyRequest calls the generic UpdateAgentPolicy builder with application/json body +func NewUpdateAgentPolicyRequest(server string, agentPolicyId string, body UpdateAgentPolicyJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewUpdateAgentPolicyRequestWithBody(server, agentPolicyId, "application/json", bodyReader) +} + +// NewUpdateAgentPolicyRequestWithBody generates requests for UpdateAgentPolicy with any type of body +func NewUpdateAgentPolicyRequestWithBody(server string, agentPolicyId string, contentType string, body io.Reader) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "agentPolicyId", runtime.ParamLocationPath, agentPolicyId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/agent_policies/%s", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("PUT", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewGetEnrollmentApiKeysRequest generates requests for GetEnrollmentApiKeys +func NewGetEnrollmentApiKeysRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/enrollment_api_keys") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil } func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error { @@ -128,4 +438,443 @@ func WithBaseURL(baseURL string) ClientOption { // ClientWithResponsesInterface is the interface specification for the client with responses above. type ClientWithResponsesInterface interface { + // CreateAgentPolicy request with any body + CreateAgentPolicyWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateAgentPolicyResponse, error) + + CreateAgentPolicyWithResponse(ctx context.Context, body CreateAgentPolicyJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateAgentPolicyResponse, error) + + // DeleteAgentPolicy request with any body + DeleteAgentPolicyWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*DeleteAgentPolicyResponse, error) + + DeleteAgentPolicyWithResponse(ctx context.Context, body DeleteAgentPolicyJSONRequestBody, reqEditors ...RequestEditorFn) (*DeleteAgentPolicyResponse, error) + + // AgentPolicyInfo request + AgentPolicyInfoWithResponse(ctx context.Context, agentPolicyId string, reqEditors ...RequestEditorFn) (*AgentPolicyInfoResponse, error) + + // UpdateAgentPolicy request with any body + UpdateAgentPolicyWithBodyWithResponse(ctx context.Context, agentPolicyId string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateAgentPolicyResponse, error) + + UpdateAgentPolicyWithResponse(ctx context.Context, agentPolicyId string, body UpdateAgentPolicyJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateAgentPolicyResponse, error) + + // GetEnrollmentApiKeys request + GetEnrollmentApiKeysWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetEnrollmentApiKeysResponse, error) +} + +type CreateAgentPolicyResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + Item *AgentPolicy `json:"item,omitempty"` + } + JSON400 *struct { + Error *string `json:"error,omitempty"` + Message *string `json:"message,omitempty"` + StatusCode *float32 `json:"statusCode,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r CreateAgentPolicyResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r CreateAgentPolicyResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type DeleteAgentPolicyResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + Id string `json:"id"` + Success bool `json:"success"` + } + JSON400 *struct { + Error *string `json:"error,omitempty"` + Message *string `json:"message,omitempty"` + StatusCode *float32 `json:"statusCode,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r DeleteAgentPolicyResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r DeleteAgentPolicyResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type AgentPolicyInfoResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + Item AgentPolicy `json:"item"` + } + JSON400 *struct { + Error *string `json:"error,omitempty"` + Message *string `json:"message,omitempty"` + StatusCode *float32 `json:"statusCode,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r AgentPolicyInfoResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r AgentPolicyInfoResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type UpdateAgentPolicyResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + Item AgentPolicy `json:"item"` + } + JSON400 *struct { + Error *string `json:"error,omitempty"` + Message *string `json:"message,omitempty"` + StatusCode *float32 `json:"statusCode,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r UpdateAgentPolicyResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r UpdateAgentPolicyResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetEnrollmentApiKeysResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + Items []EnrollmentApiKey `json:"items"` + List *[]EnrollmentApiKey `json:"list,omitempty"` + Page float32 `json:"page"` + PerPage float32 `json:"perPage"` + Total float32 `json:"total"` + } + JSON400 *struct { + Error *string `json:"error,omitempty"` + Message *string `json:"message,omitempty"` + StatusCode *float32 `json:"statusCode,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r GetEnrollmentApiKeysResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetEnrollmentApiKeysResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +// CreateAgentPolicyWithBodyWithResponse request with arbitrary body returning *CreateAgentPolicyResponse +func (c *ClientWithResponses) CreateAgentPolicyWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateAgentPolicyResponse, error) { + rsp, err := c.CreateAgentPolicyWithBody(ctx, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseCreateAgentPolicyResponse(rsp) +} + +func (c *ClientWithResponses) CreateAgentPolicyWithResponse(ctx context.Context, body CreateAgentPolicyJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateAgentPolicyResponse, error) { + rsp, err := c.CreateAgentPolicy(ctx, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseCreateAgentPolicyResponse(rsp) +} + +// DeleteAgentPolicyWithBodyWithResponse request with arbitrary body returning *DeleteAgentPolicyResponse +func (c *ClientWithResponses) DeleteAgentPolicyWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*DeleteAgentPolicyResponse, error) { + rsp, err := c.DeleteAgentPolicyWithBody(ctx, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseDeleteAgentPolicyResponse(rsp) +} + +func (c *ClientWithResponses) DeleteAgentPolicyWithResponse(ctx context.Context, body DeleteAgentPolicyJSONRequestBody, reqEditors ...RequestEditorFn) (*DeleteAgentPolicyResponse, error) { + rsp, err := c.DeleteAgentPolicy(ctx, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseDeleteAgentPolicyResponse(rsp) +} + +// AgentPolicyInfoWithResponse request returning *AgentPolicyInfoResponse +func (c *ClientWithResponses) AgentPolicyInfoWithResponse(ctx context.Context, agentPolicyId string, reqEditors ...RequestEditorFn) (*AgentPolicyInfoResponse, error) { + rsp, err := c.AgentPolicyInfo(ctx, agentPolicyId, reqEditors...) + if err != nil { + return nil, err + } + return ParseAgentPolicyInfoResponse(rsp) +} + +// UpdateAgentPolicyWithBodyWithResponse request with arbitrary body returning *UpdateAgentPolicyResponse +func (c *ClientWithResponses) UpdateAgentPolicyWithBodyWithResponse(ctx context.Context, agentPolicyId string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateAgentPolicyResponse, error) { + rsp, err := c.UpdateAgentPolicyWithBody(ctx, agentPolicyId, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseUpdateAgentPolicyResponse(rsp) +} + +func (c *ClientWithResponses) UpdateAgentPolicyWithResponse(ctx context.Context, agentPolicyId string, body UpdateAgentPolicyJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateAgentPolicyResponse, error) { + rsp, err := c.UpdateAgentPolicy(ctx, agentPolicyId, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseUpdateAgentPolicyResponse(rsp) +} + +// GetEnrollmentApiKeysWithResponse request returning *GetEnrollmentApiKeysResponse +func (c *ClientWithResponses) GetEnrollmentApiKeysWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetEnrollmentApiKeysResponse, error) { + rsp, err := c.GetEnrollmentApiKeys(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetEnrollmentApiKeysResponse(rsp) +} + +// ParseCreateAgentPolicyResponse parses an HTTP response from a CreateAgentPolicyWithResponse call +func ParseCreateAgentPolicyResponse(rsp *http.Response) (*CreateAgentPolicyResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &CreateAgentPolicyResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + Item *AgentPolicy `json:"item,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest struct { + Error *string `json:"error,omitempty"` + Message *string `json:"message,omitempty"` + StatusCode *float32 `json:"statusCode,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + } + + return response, nil +} + +// ParseDeleteAgentPolicyResponse parses an HTTP response from a DeleteAgentPolicyWithResponse call +func ParseDeleteAgentPolicyResponse(rsp *http.Response) (*DeleteAgentPolicyResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &DeleteAgentPolicyResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + Id string `json:"id"` + Success bool `json:"success"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest struct { + Error *string `json:"error,omitempty"` + Message *string `json:"message,omitempty"` + StatusCode *float32 `json:"statusCode,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + } + + return response, nil +} + +// ParseAgentPolicyInfoResponse parses an HTTP response from a AgentPolicyInfoWithResponse call +func ParseAgentPolicyInfoResponse(rsp *http.Response) (*AgentPolicyInfoResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &AgentPolicyInfoResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + Item AgentPolicy `json:"item"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest struct { + Error *string `json:"error,omitempty"` + Message *string `json:"message,omitempty"` + StatusCode *float32 `json:"statusCode,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + } + + return response, nil +} + +// ParseUpdateAgentPolicyResponse parses an HTTP response from a UpdateAgentPolicyWithResponse call +func ParseUpdateAgentPolicyResponse(rsp *http.Response) (*UpdateAgentPolicyResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &UpdateAgentPolicyResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + Item AgentPolicy `json:"item"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest struct { + Error *string `json:"error,omitempty"` + Message *string `json:"message,omitempty"` + StatusCode *float32 `json:"statusCode,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + } + + return response, nil +} + +// ParseGetEnrollmentApiKeysResponse parses an HTTP response from a GetEnrollmentApiKeysWithResponse call +func ParseGetEnrollmentApiKeysResponse(rsp *http.Response) (*GetEnrollmentApiKeysResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetEnrollmentApiKeysResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + Items []EnrollmentApiKey `json:"items"` + List *[]EnrollmentApiKey `json:"list,omitempty"` + Page float32 `json:"page"` + PerPage float32 `json:"perPage"` + Total float32 `json:"total"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest struct { + Error *string `json:"error,omitempty"` + Message *string `json:"message,omitempty"` + StatusCode *float32 `json:"statusCode,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + } + + return response, nil } diff --git a/internal/clients/fleet/fleetapi/fleetapi_gen.go b/internal/clients/fleet/fleetapi/fleetapi_gen.go index 4255eb31..ef115016 100644 --- a/internal/clients/fleet/fleetapi/fleetapi_gen.go +++ b/internal/clients/fleet/fleetapi/fleetapi_gen.go @@ -2,3 +2,181 @@ // // Code generated by github.com/deepmap/oapi-codegen version v1.12.4 DO NOT EDIT. package fleetapi + +import ( + "time" +) + +const ( + BasicAuthScopes = "basicAuth.Scopes" +) + +// Defines values for AgentPolicyMonitoringEnabled. +const ( + AgentPolicyMonitoringEnabledLogs AgentPolicyMonitoringEnabled = "logs" + AgentPolicyMonitoringEnabledMetrics AgentPolicyMonitoringEnabled = "metrics" +) + +// Defines values for AgentPolicyCreateRequestMonitoringEnabled. +const ( + AgentPolicyCreateRequestMonitoringEnabledLogs AgentPolicyCreateRequestMonitoringEnabled = "logs" + AgentPolicyCreateRequestMonitoringEnabledMetrics AgentPolicyCreateRequestMonitoringEnabled = "metrics" +) + +// Defines values for AgentPolicyUpdateRequestMonitoringEnabled. +const ( + Logs AgentPolicyUpdateRequestMonitoringEnabled = "logs" + Metrics AgentPolicyUpdateRequestMonitoringEnabled = "metrics" +) + +// AgentPolicy defines model for agent_policy. +type AgentPolicy struct { + AgentFeatures *[]struct { + Enabled bool `json:"enabled"` + Name string `json:"name"` + } `json:"agent_features,omitempty"` + Agents *float32 `json:"agents,omitempty"` + DataOutputId *string `json:"data_output_id"` + Description *string `json:"description,omitempty"` + DownloadSourceId *string `json:"download_source_id"` + FleetServerHostId *string `json:"fleet_server_host_id"` + Id string `json:"id"` + InactivityTimeout *float32 `json:"inactivity_timeout,omitempty"` + MonitoringEnabled *[]AgentPolicyMonitoringEnabled `json:"monitoring_enabled,omitempty"` + MonitoringOutputId *string `json:"monitoring_output_id"` + Name string `json:"name"` + Namespace string `json:"namespace"` + + // PackagePolicies This field is present only when retrieving a single agent policy, or when retrieving a list of agent policy with the ?full=true parameter + PackagePolicies *[]PackagePolicy `json:"package_policies,omitempty"` + Revision *float32 `json:"revision,omitempty"` + UnenrollTimeout *float32 `json:"unenroll_timeout,omitempty"` + UpdatedBy *string `json:"updated_by,omitempty"` + UpdatedOn *time.Time `json:"updated_on,omitempty"` +} + +// AgentPolicyMonitoringEnabled defines model for AgentPolicy.MonitoringEnabled. +type AgentPolicyMonitoringEnabled string + +// AgentPolicyCreateRequest defines model for agent_policy_create_request. +type AgentPolicyCreateRequest struct { + AgentFeatures *[]struct { + Enabled bool `json:"enabled"` + Name string `json:"name"` + } `json:"agent_features,omitempty"` + DataOutputId *string `json:"data_output_id"` + Description *string `json:"description,omitempty"` + DownloadSourceId *string `json:"download_source_id"` + FleetServerHostId *string `json:"fleet_server_host_id"` + Id *string `json:"id,omitempty"` + InactivityTimeout *float32 `json:"inactivity_timeout,omitempty"` + MonitoringEnabled *[]AgentPolicyCreateRequestMonitoringEnabled `json:"monitoring_enabled,omitempty"` + MonitoringOutputId *string `json:"monitoring_output_id"` + Name string `json:"name"` + Namespace string `json:"namespace"` + UnenrollTimeout *float32 `json:"unenroll_timeout,omitempty"` +} + +// AgentPolicyCreateRequestMonitoringEnabled defines model for AgentPolicyCreateRequest.MonitoringEnabled. +type AgentPolicyCreateRequestMonitoringEnabled string + +// AgentPolicyUpdateRequest defines model for agent_policy_update_request. +type AgentPolicyUpdateRequest struct { + AgentFeatures *[]struct { + Enabled bool `json:"enabled"` + Name string `json:"name"` + } `json:"agent_features,omitempty"` + DataOutputId *string `json:"data_output_id"` + Description *string `json:"description,omitempty"` + DownloadSourceId *string `json:"download_source_id"` + FleetServerHostId *string `json:"fleet_server_host_id"` + InactivityTimeout *float32 `json:"inactivity_timeout,omitempty"` + MonitoringEnabled *[]AgentPolicyUpdateRequestMonitoringEnabled `json:"monitoring_enabled,omitempty"` + MonitoringOutputId *string `json:"monitoring_output_id"` + Name string `json:"name"` + Namespace string `json:"namespace"` + UnenrollTimeout *float32 `json:"unenroll_timeout,omitempty"` +} + +// AgentPolicyUpdateRequestMonitoringEnabled defines model for AgentPolicyUpdateRequest.MonitoringEnabled. +type AgentPolicyUpdateRequestMonitoringEnabled string + +// EnrollmentApiKey defines model for enrollment_api_key. +type EnrollmentApiKey struct { + Active bool `json:"active"` + ApiKey string `json:"api_key"` + ApiKeyId string `json:"api_key_id"` + CreatedAt string `json:"created_at"` + Id string `json:"id"` + Name *string `json:"name,omitempty"` + PolicyId *string `json:"policy_id,omitempty"` +} + +// NewPackagePolicy defines model for new_package_policy. +type NewPackagePolicy struct { + Description *string `json:"description,omitempty"` + Enabled *bool `json:"enabled,omitempty"` + Inputs []struct { + Config *map[string]interface{} `json:"config,omitempty"` + Enabled bool `json:"enabled"` + Processors *[]string `json:"processors,omitempty"` + Streams *[]interface{} `json:"streams,omitempty"` + Type string `json:"type"` + Vars *map[string]interface{} `json:"vars,omitempty"` + } `json:"inputs"` + Name string `json:"name"` + Namespace *string `json:"namespace,omitempty"` + OutputId *string `json:"output_id,omitempty"` + Package *struct { + Name string `json:"name"` + Title *string `json:"title,omitempty"` + Version string `json:"version"` + } `json:"package,omitempty"` + PolicyId *string `json:"policy_id,omitempty"` +} + +// PackagePolicy defines model for package_policy. +type PackagePolicy struct { + Description *string `json:"description,omitempty"` + Enabled *bool `json:"enabled,omitempty"` + Id string `json:"id"` + Inputs []struct { + Config *map[string]interface{} `json:"config,omitempty"` + Enabled bool `json:"enabled"` + Processors *[]string `json:"processors,omitempty"` + Streams *[]interface{} `json:"streams,omitempty"` + Type string `json:"type"` + Vars *map[string]interface{} `json:"vars,omitempty"` + } `json:"inputs"` + Name string `json:"name"` + Namespace *string `json:"namespace,omitempty"` + OutputId *string `json:"output_id,omitempty"` + Package *struct { + Name string `json:"name"` + Title *string `json:"title,omitempty"` + Version string `json:"version"` + } `json:"package,omitempty"` + PolicyId *string `json:"policy_id,omitempty"` + Revision float32 `json:"revision"` +} + +// Error defines model for error. +type Error struct { + Error *string `json:"error,omitempty"` + Message *string `json:"message,omitempty"` + StatusCode *float32 `json:"statusCode,omitempty"` +} + +// DeleteAgentPolicyJSONBody defines parameters for DeleteAgentPolicy. +type DeleteAgentPolicyJSONBody struct { + AgentPolicyId string `json:"agentPolicyId"` +} + +// CreateAgentPolicyJSONRequestBody defines body for CreateAgentPolicy for application/json ContentType. +type CreateAgentPolicyJSONRequestBody = AgentPolicyCreateRequest + +// DeleteAgentPolicyJSONRequestBody defines body for DeleteAgentPolicy for application/json ContentType. +type DeleteAgentPolicyJSONRequestBody DeleteAgentPolicyJSONBody + +// UpdateAgentPolicyJSONRequestBody defines body for UpdateAgentPolicy for application/json ContentType. +type UpdateAgentPolicyJSONRequestBody = AgentPolicyUpdateRequest diff --git a/internal/clients/fleet/fleetapi/generate.go b/internal/clients/fleet/fleetapi/generate.go index 2c95bfd4..47b16ded 100644 --- a/internal/clients/fleet/fleetapi/generate.go +++ b/internal/clients/fleet/fleetapi/generate.go @@ -38,12 +38,18 @@ type Endpoint struct { Summary string `json:"summary,omitempty"` Tags []string `json:"tags,omitempty"` Responses map[string]any `json:"responses,omitempty"` + RequestBody map[string]any `json:"requestBody,omitempty"` OperationID string `json:"operationId,omitempty"` Parameters []map[string]any `json:"parameters,omitempty"` Deprecated bool `json:"deprecated,omitempty"` } -var includePaths = map[string][]string{} +var includePaths = map[string][]string{ + "/agent_policies": {"post"}, + "/agent_policies/{agentPolicyId}": {"get", "put"}, + "/agent_policies/delete": {"post"}, + "/enrollment_api_keys": {"get"}, +} func downloadFile(url string) ([]byte, error) { resp, err := http.Get(url) diff --git a/internal/fleet/agent_policy_resource.go b/internal/fleet/agent_policy_resource.go new file mode 100644 index 00000000..d7857550 --- /dev/null +++ b/internal/fleet/agent_policy_resource.go @@ -0,0 +1,281 @@ +package fleet + +import ( + "context" + + "github.com/elastic/terraform-provider-elasticstack/internal/clients/fleet" + "github.com/elastic/terraform-provider-elasticstack/internal/clients/fleet/fleetapi" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + monitorLogs = "logs" + monitorMetrics = "metrics" +) + +func ResourceAgentPolicy() *schema.Resource { + agentPolicySchema := map[string]*schema.Schema{ + "policy_id": { + Description: "Unique identifier of the agent policy.", + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + }, + "name": { + Description: "The name of the agent policy.", + Type: schema.TypeString, + Required: true, + }, + "namespace": { + Description: "The namespace of the agent policy.", + Type: schema.TypeString, + Required: true, + }, + "description": { + Description: "The description of the agent policy.", + Type: schema.TypeString, + Optional: true, + }, + "data_output_id": { + Description: "The identifier for the data output.", + Type: schema.TypeString, + Optional: true, + }, + "monitoring_output_id": { + Description: "The identifier for monitoring output.", + Type: schema.TypeString, + Optional: true, + }, + "fleet_server_host_id": { + Description: "The identifier for the Fleet server host.", + Type: schema.TypeString, + Optional: true, + }, + "download_source_id": { + Description: "The identifier for the Elastic Agent binary download server.", + Type: schema.TypeString, + Optional: true, + }, + "sys_monitoring": { + Description: "Enable collection of system logs and metrics.", + Type: schema.TypeBool, + Optional: true, + }, + "monitor_logs": { + Description: "Enable collection of agent logs.", + Type: schema.TypeBool, + Optional: true, + }, + "monitor_metrics": { + Description: "Enable collection of agent metrics.", + Type: schema.TypeBool, + Optional: true, + }, + } + + return &schema.Resource{ + Description: "Creates a new Fleet Agent Policy. See https://www.elastic.co/guide/en/fleet/current/agent-policy.html", + + CreateContext: resourceAgentPolicyCreate, + ReadContext: resourceAgentPolicyRead, + UpdateContext: resourceAgentPolicyUpdate, + DeleteContext: resourceAgentPolicyDelete, + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: agentPolicySchema, + } +} + +func resourceAgentPolicyCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + fleetClient, diags := getFleetClient(d, meta) + if diags.HasError() { + return diags + } + + req := fleetapi.AgentPolicyCreateRequest{ + Name: d.Get("name").(string), + Namespace: d.Get("namespace").(string), + } + + if value := d.Get("policy_id").(string); value != "" { + req.Id = &value + } + if value := d.Get("description").(string); value != "" { + req.Description = &value + } + if value := d.Get("data_output_id").(string); value != "" { + req.DataOutputId = &value + } + if value := d.Get("download_source_id").(string); value != "" { + req.DownloadSourceId = &value + } + if value := d.Get("fleet_server_host_id").(string); value != "" { + req.FleetServerHostId = &value + } + if value := d.Get("monitoring_output_id").(string); value != "" { + req.MonitoringOutputId = &value + } + + var monitoringValues []fleetapi.AgentPolicyCreateRequestMonitoringEnabled + if value := d.Get("monitor_logs").(bool); value { + monitoringValues = append(monitoringValues, monitorLogs) + } + if value := d.Get("monitor_metrics").(bool); value { + monitoringValues = append(monitoringValues, monitorMetrics) + } + if len(monitoringValues) > 0 { + req.MonitoringEnabled = &monitoringValues + } + + policy, diags := fleet.CreateAgentPolicy(ctx, fleetClient, req) + if diags.HasError() { + return diags + } + + d.SetId(policy.Id) + if err := d.Set("policy_id", policy.Id); err != nil { + return diag.FromErr(err) + } + + return resourceAgentPolicyRead(ctx, d, meta) +} + +func resourceAgentPolicyUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + fleetClient, diags := getFleetClient(d, meta) + if diags.HasError() { + return diags + } + + id := d.Get("policy_id").(string) + d.SetId(id) + + req := fleetapi.AgentPolicyUpdateRequest{ + Name: d.Get("name").(string), + Namespace: d.Get("namespace").(string), + } + + if value := d.Get("description").(string); value != "" { + req.Description = &value + } + if value := d.Get("data_output_id").(string); value != "" { + req.DataOutputId = &value + } + if value := d.Get("download_source_id").(string); value != "" { + req.DownloadSourceId = &value + } + if value := d.Get("fleet_server_host_id").(string); value != "" { + req.FleetServerHostId = &value + } + if value := d.Get("monitoring_output_id").(string); value != "" { + req.MonitoringOutputId = &value + } + + var monitoringValues []fleetapi.AgentPolicyUpdateRequestMonitoringEnabled + if value := d.Get("monitor_logs").(bool); value { + monitoringValues = append(monitoringValues, monitorLogs) + } + if value := d.Get("monitor_metrics").(bool); value { + monitoringValues = append(monitoringValues, monitorMetrics) + } + if len(monitoringValues) > 0 { + req.MonitoringEnabled = &monitoringValues + } + _, diags = fleet.UpdateAgentPolicy(ctx, fleetClient, id, req) + if diags.HasError() { + return diags + } + + return resourceAgentPolicyRead(ctx, d, meta) +} + +func resourceAgentPolicyRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + fleetClient, diags := getFleetClient(d, meta) + if diags.HasError() { + return diags + } + + id := d.Get("policy_id").(string) + d.SetId(id) + + agentPolicy, diags := fleet.ReadAgentPolicy(ctx, fleetClient, id) + if diags.HasError() { + return diags + } + + // Not found. + if agentPolicy == nil { + d.SetId("") + return nil + } + + if err := d.Set("name", agentPolicy.Name); err != nil { + return diag.FromErr(err) + } + if err := d.Set("namespace", agentPolicy.Namespace); err != nil { + return diag.FromErr(err) + } + if agentPolicy.Description != nil { + if err := d.Set("description", *agentPolicy.Description); err != nil { + return diag.FromErr(err) + } + } + if agentPolicy.DataOutputId != nil { + if err := d.Set("data_output_id", *agentPolicy.DataOutputId); err != nil { + return diag.FromErr(err) + } + } + if agentPolicy.DownloadSourceId != nil { + if err := d.Set("download_source_id", *agentPolicy.DownloadSourceId); err != nil { + return diag.FromErr(err) + } + } + if agentPolicy.FleetServerHostId != nil { + if err := d.Set("fleet_server_host_id", *agentPolicy.FleetServerHostId); err != nil { + return diag.FromErr(err) + } + } + if agentPolicy.MonitoringOutputId != nil { + if err := d.Set("monitoring_output_id", *agentPolicy.MonitoringOutputId); err != nil { + return diag.FromErr(err) + } + } + if agentPolicy.MonitoringEnabled != nil { + for _, v := range *agentPolicy.MonitoringEnabled { + switch v { + case monitorLogs: + if err := d.Set("monitor_logs", true); err != nil { + return diag.FromErr(err) + } + case monitorMetrics: + if err := d.Set("monitor_logs", true); err != nil { + return diag.FromErr(err) + + } + } + } + } + + return nil +} + +func resourceAgentPolicyDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + fleetClient, diags := getFleetClient(d, meta) + if diags.HasError() { + return diags + } + + id := d.Get("policy_id").(string) + d.SetId(id) + + if diags = fleet.DeleteAgentPolicy(ctx, fleetClient, id); diags.HasError() { + return diags + } + d.SetId("") + + return diags +} diff --git a/internal/fleet/agent_policy_resource_test.go b/internal/fleet/agent_policy_resource_test.go new file mode 100644 index 00000000..de146ae8 --- /dev/null +++ b/internal/fleet/agent_policy_resource_test.go @@ -0,0 +1,121 @@ +package fleet_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/versionutils" + "github.com/hashicorp/go-version" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +var minVersionAgentPolicy = version.Must(version.NewVersion("8.6.0")) + +func TestAccResourceAgentPolicy(t *testing.T) { + policyName := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + CheckDestroy: checkResourceAgentPolicyDestroy, + ProtoV5ProviderFactories: acctest.Providers, + Steps: []resource.TestStep{ + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionAgentPolicy), + Config: testAccResourceAgentPolicyCreate(policyName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "name", fmt.Sprintf("Policy %s", policyName)), + resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "namespace", "default"), + resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "description", "Test Agent Policy"), + resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "monitor_logs", "true"), + resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "monitor_metrics", "true"), + ), + }, + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionAgentPolicy), + Config: testAccResourceAgentPolicyUpdate(policyName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "name", fmt.Sprintf("Updated Policy %s", policyName)), + resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "namespace", "default"), + resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "description", "This policy was updated"), + resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "monitor_logs", "true"), + resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "monitor_metrics", "true"), + ), + }, + }, + }) +} + +func testAccResourceAgentPolicyCreate(id string) string { + return fmt.Sprintf(` +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_fleet_agent_policy" "test_policy" { + name = "%s" + namespace = "default" + description = "Test Agent Policy" + monitor_logs = true + monitor_metrics = true +} + +data "elasticstack_fleet_enrollment_tokens" "test_policy" { + policy_id = elasticstack_fleet_agent_policy.test_policy.policy_id +} + +`, fmt.Sprintf("Policy %s", id)) +} + +func testAccResourceAgentPolicyUpdate(id string) string { + return fmt.Sprintf(` +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_fleet_agent_policy" "test_policy" { + name = "%s" + namespace = "default" + description = "This policy was updated" + monitor_logs = true + monitor_metrics = true +} + +data "elasticstack_fleet_enrollment_tokens" "test_policy" { + policy_id = elasticstack_fleet_agent_policy.test_policy.policy_id +} +`, fmt.Sprintf("Updated Policy %s", 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 + } + packagePolicy, diag := fleet.ReadAgentPolicy(context.Background(), fleetClient, rs.Primary.ID) + if diag.HasError() { + return fmt.Errorf(diag[0].Summary) + } + if packagePolicy != nil { + return fmt.Errorf("agent policy id=%v still exists, but it should have been removed", rs.Primary.ID) + } + } + return nil +} diff --git a/internal/fleet/enrollment_tokens_data_source.go b/internal/fleet/enrollment_tokens_data_source.go new file mode 100644 index 00000000..ccf3272a --- /dev/null +++ b/internal/fleet/enrollment_tokens_data_source.go @@ -0,0 +1,127 @@ +package fleet + +import ( + "context" + + "github.com/elastic/terraform-provider-elasticstack/internal/clients/fleet" + "github.com/elastic/terraform-provider-elasticstack/internal/utils" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceEnrollmentTokens() *schema.Resource { + enrollmentTokenSchema := map[string]*schema.Schema{ + "policy_id": { + Description: "The identifier of the target agent policy. When provided, only the enrollment tokens associated with this agent policy will be selected. Omit this value to select all enrollment tokens.", + Type: schema.TypeString, + Optional: true, + }, + "tokens": { + Description: "A list of enrollment tokens.", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key_id": { + Description: "The unique identifier of the enrollment token.", + Type: schema.TypeString, + Computed: true, + }, + "api_key": { + Description: "The API key.", + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + "api_key_id": { + Description: "The API key identifier.", + Type: schema.TypeString, + Computed: true, + }, + "created_at": { + Description: "The time at which the enrollment token was created.", + Type: schema.TypeString, + Computed: true, + }, + "name": { + Description: "The name of the enrollment token.", + Type: schema.TypeString, + Computed: true, + }, + "active": { + Description: "Indicates if the enrollment token is active.", + Type: schema.TypeBool, + Computed: true, + }, + "policy_id": { + Description: "The identifier of the associated agent policy.", + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + } + + return &schema.Resource{ + Description: "Retrieves Elasticsearch API keys used to enroll Elastic Agents in Fleet. See: https://www.elastic.co/guide/en/fleet/current/fleet-enrollment-tokens.html", + + ReadContext: dataSourceEnrollmentTokensRead, + + Schema: enrollmentTokenSchema, + } +} + +func dataSourceEnrollmentTokensRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + fleetClient, diags := getFleetClient(d, meta) + if diags.HasError() { + return diags + } + + policyID := d.Get("policy_id").(string) + + allTokens, diags := fleet.AllEnrollmentTokens(ctx, fleetClient) + if diags.HasError() { + return diags + } + + var enrollmentTokens []map[string]any + for _, v := range allTokens { + if policyID != "" && v.PolicyId != nil && *v.PolicyId != policyID { + continue + } + + keyData := map[string]any{ + "api_key": v.ApiKey, + "api_key_id": v.ApiKeyId, + "created_at": v.CreatedAt, + "active": v.Active, + } + if v.Name != nil { + keyData["name"] = *v.Name + } + if v.PolicyId != nil { + keyData["policy_id"] = *v.PolicyId + } + + enrollmentTokens = append(enrollmentTokens, keyData) + } + + if enrollmentTokens != nil { + if err := d.Set("tokens", enrollmentTokens); err != nil { + return diag.FromErr(err) + } + } + + if policyID != "" { + d.SetId(policyID) + } else { + hash, err := utils.StringToHash(fleetClient.URL) + if err != nil { + return diag.FromErr(err) + } + d.SetId(*hash) + } + + return diags +} diff --git a/internal/fleet/enrollment_tokens_data_source_test.go b/internal/fleet/enrollment_tokens_data_source_test.go new file mode 100644 index 00000000..e8211f50 --- /dev/null +++ b/internal/fleet/enrollment_tokens_data_source_test.go @@ -0,0 +1,48 @@ +package fleet_test + +import ( + "testing" + + "github.com/elastic/terraform-provider-elasticstack/internal/acctest" + "github.com/elastic/terraform-provider-elasticstack/internal/versionutils" + "github.com/hashicorp/go-version" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +var minVersionEnrollmentTokens = version.Must(version.NewVersion("8.6.0")) + +func TestAccDataSourceEnrollmentTokens(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ProtoV5ProviderFactories: acctest.Providers, + CheckDestroy: checkResourceAgentPolicyDestroy, + Steps: []resource.TestStep{ + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionEnrollmentTokens), + Config: testAccDataSourceEnrollmentToken, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.elasticstack_fleet_enrollment_tokens.test", "policy_id", "223b1bf8-240f-463f-8466-5062670d0754"), + resource.TestCheckResourceAttr("data.elasticstack_fleet_enrollment_tokens.test", "tokens.0.policy_id", "223b1bf8-240f-463f-8466-5062670d0754"), + ), + }, + }, + }) +} + +const testAccDataSourceEnrollmentToken = ` +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_fleet_agent_policy" "test" { + policy_id = "223b1bf8-240f-463f-8466-5062670d0754" + name = "Test Agent Policy" + namespace = "default" + description = "Agent Policy for testing Enrollment Tokens" +} + +data "elasticstack_fleet_enrollment_tokens" "test" { + policy_id = elasticstack_fleet_agent_policy.test.policy_id +} +` diff --git a/internal/fleet/shared.go b/internal/fleet/shared.go new file mode 100644 index 00000000..ee8a590c --- /dev/null +++ b/internal/fleet/shared.go @@ -0,0 +1,21 @@ +package fleet + +import ( + "github.com/elastic/terraform-provider-elasticstack/internal/clients" + "github.com/elastic/terraform-provider-elasticstack/internal/clients/fleet" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func getFleetClient(d *schema.ResourceData, meta interface{}) (*fleet.Client, diag.Diagnostics) { + client, diags := clients.NewApiClient(d, meta) + if diags.HasError() { + return nil, diags + } + fleetClient, err := client.GetFleetClient() + if err != nil { + return nil, diag.FromErr(err) + } + + return fleetClient, nil +} diff --git a/provider/provider.go b/provider/provider.go index 8f306e4d..5fa0dba4 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -10,6 +10,7 @@ import ( "github.com/elastic/terraform-provider-elasticstack/internal/elasticsearch/security" "github.com/elastic/terraform-provider-elasticstack/internal/elasticsearch/transform" "github.com/elastic/terraform-provider-elasticstack/internal/elasticsearch/watcher" + "github.com/elastic/terraform-provider-elasticstack/internal/fleet" "github.com/elastic/terraform-provider-elasticstack/internal/kibana" providerSchema "github.com/elastic/terraform-provider-elasticstack/internal/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -74,6 +75,8 @@ func New(version string) *schema.Provider { "elasticstack_elasticsearch_security_user": security.DataSourceUser(), "elasticstack_elasticsearch_snapshot_repository": cluster.DataSourceSnapshotRespository(), "elasticstack_elasticsearch_enrich_policy": enrich.DataSourceEnrichPolicy(), + + "elasticstack_fleet_enrollment_tokens": fleet.DataSourceEnrollmentTokens(), }, ResourcesMap: map[string]*schema.Resource{ "elasticstack_elasticsearch_cluster_settings": cluster.ResourceSettings(), @@ -98,6 +101,8 @@ func New(version string) *schema.Provider { "elasticstack_kibana_alerting_rule": kibana.ResourceAlertingRule(), "elasticstack_kibana_space": kibana.ResourceSpace(), + + "elasticstack_fleet_agent_policy": fleet.ResourceAgentPolicy(), }, } diff --git a/templates/data-sources/fleet_enrollment_tokens.md.tmpl b/templates/data-sources/fleet_enrollment_tokens.md.tmpl new file mode 100644 index 00000000..c3fcd187 --- /dev/null +++ b/templates/data-sources/fleet_enrollment_tokens.md.tmpl @@ -0,0 +1,17 @@ +--- +subcategory: "Fleet" +layout: "" +page_title: "Elasticstack: elasticstack_fleet_enrollment_tokens Data Source" +description: |- + Gets information about Fleet Enrollment Tokens. See https://www.elastic.co/guide/en/fleet/current/fleet-enrollment-tokens.html +--- + +# Data Source: elasticstack_fleet_enrollment_tokens + +This data source provides information about Fleet Enrollment Tokens. + +## Example Usage + +{{ tffile "examples/data-sources/elasticstack_fleet_enrollment_tokens/data-source.tf" }} + +{{ .SchemaMarkdown | trimspace }} diff --git a/templates/resources/fleet_agent_policy.md.tmpl b/templates/resources/fleet_agent_policy.md.tmpl new file mode 100644 index 00000000..2c2ade22 --- /dev/null +++ b/templates/resources/fleet_agent_policy.md.tmpl @@ -0,0 +1,23 @@ +--- +subcategory: "Fleet" +layout: "" +page_title: "Elasticstack: elasticstack_fleet_agent_policy Resource" +description: |- + Creates or updates a Fleet Agent Policy. +--- + +# Resource: elasticstack_fleet_agent_policy + +Creates or updates a Fleet Agent Policy. See https://www.elastic.co/guide/en/fleet/current/fleet-api-docs.html#create-agent-policy-api + +## Example Usage + +{{ tffile "examples/resources/elasticstack_fleet_agent_policy/resource.tf" }} + +{{ .SchemaMarkdown | trimspace }} + +## Import + +Import is supported using the following syntax: + +{{ codefile "shell" "examples/resources/elasticstack_fleet_agent_policy/import.sh" }}