From db09c21e1f7fa2f3f79b051bb7a0b8aa6feb03cb Mon Sep 17 00:00:00 2001 From: Toby Brain Date: Mon, 7 Jul 2025 09:49:53 +1000 Subject: [PATCH 01/11] Add agent configuration operations to generated client --- generated/kbapi/kibana.gen.go | 693 ++++++++++++++++++++++++++++ generated/kbapi/transform_schema.go | 1 + 2 files changed, 694 insertions(+) diff --git a/generated/kbapi/kibana.gen.go b/generated/kbapi/kibana.gen.go index 060792f2c..750c00590 100644 --- a/generated/kbapi/kibana.gen.go +++ b/generated/kbapi/kibana.gen.go @@ -498,6 +498,26 @@ const ( UpdateOutputSslVerificationModeStrict UpdateOutputSslVerificationMode = "strict" ) +// Defines values for APMUIElasticApiVersion. +const ( + APMUIElasticApiVersionN20231031 APMUIElasticApiVersion = "2023-10-31" +) + +// Defines values for DeleteAgentConfigurationParamsElasticApiVersion. +const ( + DeleteAgentConfigurationParamsElasticApiVersionN20231031 DeleteAgentConfigurationParamsElasticApiVersion = "2023-10-31" +) + +// Defines values for GetAgentConfigurationsParamsElasticApiVersion. +const ( + GetAgentConfigurationsParamsElasticApiVersionN20231031 GetAgentConfigurationsParamsElasticApiVersion = "2023-10-31" +) + +// Defines values for CreateUpdateAgentConfigurationParamsElasticApiVersion. +const ( + CreateUpdateAgentConfigurationParamsElasticApiVersionN20231031 CreateUpdateAgentConfigurationParamsElasticApiVersion = "2023-10-31" +) + // Defines values for GetFleetAgentPoliciesParamsSortOrder. const ( GetFleetAgentPoliciesParamsSortOrderAsc GetFleetAgentPoliciesParamsSortOrder = "asc" @@ -580,6 +600,111 @@ const ( Simplified PutFleetPackagePoliciesPackagepolicyidParamsFormat = "simplified" ) +// APMUI400Response defines model for APM_UI_400_response. +type APMUI400Response struct { + // Error Error type + Error *string `json:"error,omitempty"` + + // Message Error message + Message *string `json:"message,omitempty"` + + // StatusCode Error status code + StatusCode *float32 `json:"statusCode,omitempty"` +} + +// APMUI401Response defines model for APM_UI_401_response. +type APMUI401Response struct { + // Error Error type + Error *string `json:"error,omitempty"` + + // Message Error message + Message *string `json:"message,omitempty"` + + // StatusCode Error status code + StatusCode *float32 `json:"statusCode,omitempty"` +} + +// APMUI403Response defines model for APM_UI_403_response. +type APMUI403Response struct { + // Error Error type + Error *string `json:"error,omitempty"` + + // Message Error message + Message *string `json:"message,omitempty"` + + // StatusCode Error status code + StatusCode *float32 `json:"statusCode,omitempty"` +} + +// APMUI404Response defines model for APM_UI_404_response. +type APMUI404Response struct { + // Error Error type + Error *string `json:"error,omitempty"` + + // Message Error message + Message *string `json:"message,omitempty"` + + // StatusCode Error status code + StatusCode *float32 `json:"statusCode,omitempty"` +} + +// APMUIAgentConfigurationIntakeObject defines model for APM_UI_agent_configuration_intake_object. +type APMUIAgentConfigurationIntakeObject struct { + // AgentName The agent name is used by the UI to determine which settings to display. + AgentName *string `json:"agent_name,omitempty"` + + // Service Service + Service APMUIServiceObject `json:"service"` + + // Settings Agent configuration settings + Settings APMUISettingsObject `json:"settings"` +} + +// APMUIAgentConfigurationObject Agent configuration +type APMUIAgentConfigurationObject struct { + // Timestamp Timestamp + Timestamp float32 `json:"@timestamp"` + + // AgentName Agent name + AgentName *string `json:"agent_name,omitempty"` + + // AppliedByAgent Applied by agent + AppliedByAgent *bool `json:"applied_by_agent,omitempty"` + + // Etag `etag` is sent by the APM agent to indicate the `etag` of the last successfully applied configuration. If the `etag` matches an existing configuration its `applied_by_agent` property will be set to `true`. Every time a configuration is edited `applied_by_agent` is reset to `false`. + Etag string `json:"etag"` + + // Service Service + Service APMUIServiceObject `json:"service"` + + // Settings Agent configuration settings + Settings APMUISettingsObject `json:"settings"` +} + +// APMUIAgentConfigurationsResponse defines model for APM_UI_agent_configurations_response. +type APMUIAgentConfigurationsResponse struct { + // Configurations Agent configuration + Configurations *[]APMUIAgentConfigurationObject `json:"configurations,omitempty"` +} + +// APMUIDeleteAgentConfigurationsResponse defines model for APM_UI_delete_agent_configurations_response. +type APMUIDeleteAgentConfigurationsResponse struct { + // Result Result + Result *string `json:"result,omitempty"` +} + +// APMUIServiceObject Service +type APMUIServiceObject struct { + // Environment The environment of the service. + Environment *string `json:"environment,omitempty"` + + // Name The name of the service. + Name *string `json:"name,omitempty"` +} + +// APMUISettingsObject Agent configuration settings +type APMUISettingsObject map[string]string + // DataViews400Response defines model for Data_views_400_response. type DataViews400Response struct { Error string `json:"error"` @@ -2900,12 +3025,45 @@ type UpdateOutputUnion struct { union json.RawMessage } +// APMUIElasticApiVersion defines model for APM_UI_elastic_api_version. +type APMUIElasticApiVersion string + // DataViewsViewId defines model for Data_views_view_id. type DataViewsViewId = string // SpaceId defines model for spaceId. type SpaceId = string +// DeleteAgentConfigurationParams defines parameters for DeleteAgentConfiguration. +type DeleteAgentConfigurationParams struct { + // ElasticApiVersion The version of the API to use + ElasticApiVersion DeleteAgentConfigurationParamsElasticApiVersion `json:"elastic-api-version"` +} + +// DeleteAgentConfigurationParamsElasticApiVersion defines parameters for DeleteAgentConfiguration. +type DeleteAgentConfigurationParamsElasticApiVersion string + +// GetAgentConfigurationsParams defines parameters for GetAgentConfigurations. +type GetAgentConfigurationsParams struct { + // ElasticApiVersion The version of the API to use + ElasticApiVersion GetAgentConfigurationsParamsElasticApiVersion `json:"elastic-api-version"` +} + +// GetAgentConfigurationsParamsElasticApiVersion defines parameters for GetAgentConfigurations. +type GetAgentConfigurationsParamsElasticApiVersion string + +// CreateUpdateAgentConfigurationParams defines parameters for CreateUpdateAgentConfiguration. +type CreateUpdateAgentConfigurationParams struct { + // Overwrite If the config exists ?overwrite=true is required + Overwrite *bool `form:"overwrite,omitempty" json:"overwrite,omitempty"` + + // ElasticApiVersion The version of the API to use + ElasticApiVersion CreateUpdateAgentConfigurationParamsElasticApiVersion `json:"elastic-api-version"` +} + +// CreateUpdateAgentConfigurationParamsElasticApiVersion defines parameters for CreateUpdateAgentConfiguration. +type CreateUpdateAgentConfigurationParamsElasticApiVersion string + // GetFleetAgentPoliciesParams defines parameters for GetFleetAgentPolicies. type GetFleetAgentPoliciesParams struct { Page *float32 `form:"page,omitempty" json:"page,omitempty"` @@ -3369,6 +3527,12 @@ type PutParameterJSONBody struct { Value *string `json:"value,omitempty"` } +// DeleteAgentConfigurationJSONRequestBody defines body for DeleteAgentConfiguration for application/json ContentType. +type DeleteAgentConfigurationJSONRequestBody = APMUIServiceObject + +// CreateUpdateAgentConfigurationJSONRequestBody defines body for CreateUpdateAgentConfiguration for application/json ContentType. +type CreateUpdateAgentConfigurationJSONRequestBody = APMUIAgentConfigurationIntakeObject + // PostFleetAgentPoliciesJSONRequestBody defines body for PostFleetAgentPolicies for application/json ContentType. type PostFleetAgentPoliciesJSONRequestBody PostFleetAgentPoliciesJSONBody @@ -14268,6 +14432,19 @@ func WithRequestEditorFn(fn RequestEditorFn) ClientOption { // The interface specification for the client above. type ClientInterface interface { + // DeleteAgentConfigurationWithBody request with any body + DeleteAgentConfigurationWithBody(ctx context.Context, params *DeleteAgentConfigurationParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + DeleteAgentConfiguration(ctx context.Context, params *DeleteAgentConfigurationParams, body DeleteAgentConfigurationJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetAgentConfigurations request + GetAgentConfigurations(ctx context.Context, params *GetAgentConfigurationsParams, reqEditors ...RequestEditorFn) (*http.Response, error) + + // CreateUpdateAgentConfigurationWithBody request with any body + CreateUpdateAgentConfigurationWithBody(ctx context.Context, params *CreateUpdateAgentConfigurationParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + CreateUpdateAgentConfiguration(ctx context.Context, params *CreateUpdateAgentConfigurationParams, body CreateUpdateAgentConfigurationJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + // GetFleetAgentPolicies request GetFleetAgentPolicies(ctx context.Context, params *GetFleetAgentPoliciesParams, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -14402,6 +14579,66 @@ type ClientInterface interface { UpdateDataViewDefault(ctx context.Context, spaceId SpaceId, viewId DataViewsViewId, body UpdateDataViewDefaultJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) } +func (c *Client) DeleteAgentConfigurationWithBody(ctx context.Context, params *DeleteAgentConfigurationParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewDeleteAgentConfigurationRequestWithBody(c.Server, params, 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) DeleteAgentConfiguration(ctx context.Context, params *DeleteAgentConfigurationParams, body DeleteAgentConfigurationJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewDeleteAgentConfigurationRequest(c.Server, params, 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) GetAgentConfigurations(ctx context.Context, params *GetAgentConfigurationsParams, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetAgentConfigurationsRequest(c.Server, params) + 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) CreateUpdateAgentConfigurationWithBody(ctx context.Context, params *CreateUpdateAgentConfigurationParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewCreateUpdateAgentConfigurationRequestWithBody(c.Server, params, 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) CreateUpdateAgentConfiguration(ctx context.Context, params *CreateUpdateAgentConfigurationParams, body CreateUpdateAgentConfigurationJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewCreateUpdateAgentConfigurationRequest(c.Server, params, 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) GetFleetAgentPolicies(ctx context.Context, params *GetFleetAgentPoliciesParams, reqEditors ...RequestEditorFn) (*http.Response, error) { req, err := NewGetFleetAgentPoliciesRequest(c.Server, params) if err != nil { @@ -14990,6 +15227,174 @@ func (c *Client) UpdateDataViewDefault(ctx context.Context, spaceId SpaceId, vie return c.Client.Do(req) } +// NewDeleteAgentConfigurationRequest calls the generic DeleteAgentConfiguration builder with application/json body +func NewDeleteAgentConfigurationRequest(server string, params *DeleteAgentConfigurationParams, body DeleteAgentConfigurationJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewDeleteAgentConfigurationRequestWithBody(server, params, "application/json", bodyReader) +} + +// NewDeleteAgentConfigurationRequestWithBody generates requests for DeleteAgentConfiguration with any type of body +func NewDeleteAgentConfigurationRequestWithBody(server string, params *DeleteAgentConfigurationParams, 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("/api/apm/settings/agent-configuration") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("DELETE", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + if params != nil { + + var headerParam0 string + + headerParam0, err = runtime.StyleParamWithLocation("simple", false, "elastic-api-version", runtime.ParamLocationHeader, params.ElasticApiVersion) + if err != nil { + return nil, err + } + + req.Header.Set("elastic-api-version", headerParam0) + + } + + return req, nil +} + +// NewGetAgentConfigurationsRequest generates requests for GetAgentConfigurations +func NewGetAgentConfigurationsRequest(server string, params *GetAgentConfigurationsParams) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/api/apm/settings/agent-configuration") + 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 + } + + if params != nil { + + var headerParam0 string + + headerParam0, err = runtime.StyleParamWithLocation("simple", false, "elastic-api-version", runtime.ParamLocationHeader, params.ElasticApiVersion) + if err != nil { + return nil, err + } + + req.Header.Set("elastic-api-version", headerParam0) + + } + + return req, nil +} + +// NewCreateUpdateAgentConfigurationRequest calls the generic CreateUpdateAgentConfiguration builder with application/json body +func NewCreateUpdateAgentConfigurationRequest(server string, params *CreateUpdateAgentConfigurationParams, body CreateUpdateAgentConfigurationJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewCreateUpdateAgentConfigurationRequestWithBody(server, params, "application/json", bodyReader) +} + +// NewCreateUpdateAgentConfigurationRequestWithBody generates requests for CreateUpdateAgentConfiguration with any type of body +func NewCreateUpdateAgentConfigurationRequestWithBody(server string, params *CreateUpdateAgentConfigurationParams, 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("/api/apm/settings/agent-configuration") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + if params != nil { + queryValues := queryURL.Query() + + if params.Overwrite != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "overwrite", runtime.ParamLocationQuery, *params.Overwrite); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + queryURL.RawQuery = queryValues.Encode() + } + + req, err := http.NewRequest("PUT", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + if params != nil { + + var headerParam0 string + + headerParam0, err = runtime.StyleParamWithLocation("simple", false, "elastic-api-version", runtime.ParamLocationHeader, params.ElasticApiVersion) + if err != nil { + return nil, err + } + + req.Header.Set("elastic-api-version", headerParam0) + + } + + return req, nil +} + // NewGetFleetAgentPoliciesRequest generates requests for GetFleetAgentPolicies func NewGetFleetAgentPoliciesRequest(server string, params *GetFleetAgentPoliciesParams) (*http.Request, error) { var err error @@ -17120,6 +17525,19 @@ func WithBaseURL(baseURL string) ClientOption { // ClientWithResponsesInterface is the interface specification for the client with responses above. type ClientWithResponsesInterface interface { + // DeleteAgentConfigurationWithBodyWithResponse request with any body + DeleteAgentConfigurationWithBodyWithResponse(ctx context.Context, params *DeleteAgentConfigurationParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*DeleteAgentConfigurationResponse, error) + + DeleteAgentConfigurationWithResponse(ctx context.Context, params *DeleteAgentConfigurationParams, body DeleteAgentConfigurationJSONRequestBody, reqEditors ...RequestEditorFn) (*DeleteAgentConfigurationResponse, error) + + // GetAgentConfigurationsWithResponse request + GetAgentConfigurationsWithResponse(ctx context.Context, params *GetAgentConfigurationsParams, reqEditors ...RequestEditorFn) (*GetAgentConfigurationsResponse, error) + + // CreateUpdateAgentConfigurationWithBodyWithResponse request with any body + CreateUpdateAgentConfigurationWithBodyWithResponse(ctx context.Context, params *CreateUpdateAgentConfigurationParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateUpdateAgentConfigurationResponse, error) + + CreateUpdateAgentConfigurationWithResponse(ctx context.Context, params *CreateUpdateAgentConfigurationParams, body CreateUpdateAgentConfigurationJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateUpdateAgentConfigurationResponse, error) + // GetFleetAgentPoliciesWithResponse request GetFleetAgentPoliciesWithResponse(ctx context.Context, params *GetFleetAgentPoliciesParams, reqEditors ...RequestEditorFn) (*GetFleetAgentPoliciesResponse, error) @@ -17254,6 +17672,83 @@ type ClientWithResponsesInterface interface { UpdateDataViewDefaultWithResponse(ctx context.Context, spaceId SpaceId, viewId DataViewsViewId, body UpdateDataViewDefaultJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateDataViewDefaultResponse, error) } +type DeleteAgentConfigurationResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *APMUIDeleteAgentConfigurationsResponse + JSON400 *APMUI400Response + JSON401 *APMUI401Response + JSON403 *APMUI403Response + JSON404 *APMUI404Response +} + +// Status returns HTTPResponse.Status +func (r DeleteAgentConfigurationResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r DeleteAgentConfigurationResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetAgentConfigurationsResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *APMUIAgentConfigurationsResponse + JSON400 *APMUI400Response + JSON401 *APMUI401Response + JSON404 *APMUI404Response +} + +// Status returns HTTPResponse.Status +func (r GetAgentConfigurationsResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetAgentConfigurationsResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type CreateUpdateAgentConfigurationResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *map[string]interface{} + JSON400 *APMUI400Response + JSON401 *APMUI401Response + JSON403 *APMUI403Response + JSON404 *APMUI404Response +} + +// Status returns HTTPResponse.Status +func (r CreateUpdateAgentConfigurationResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r CreateUpdateAgentConfigurationResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + type GetFleetAgentPoliciesResponse struct { Body []byte HTTPResponse *http.Response @@ -18360,6 +18855,49 @@ func (r UpdateDataViewDefaultResponse) StatusCode() int { return 0 } +// DeleteAgentConfigurationWithBodyWithResponse request with arbitrary body returning *DeleteAgentConfigurationResponse +func (c *ClientWithResponses) DeleteAgentConfigurationWithBodyWithResponse(ctx context.Context, params *DeleteAgentConfigurationParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*DeleteAgentConfigurationResponse, error) { + rsp, err := c.DeleteAgentConfigurationWithBody(ctx, params, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseDeleteAgentConfigurationResponse(rsp) +} + +func (c *ClientWithResponses) DeleteAgentConfigurationWithResponse(ctx context.Context, params *DeleteAgentConfigurationParams, body DeleteAgentConfigurationJSONRequestBody, reqEditors ...RequestEditorFn) (*DeleteAgentConfigurationResponse, error) { + rsp, err := c.DeleteAgentConfiguration(ctx, params, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseDeleteAgentConfigurationResponse(rsp) +} + +// GetAgentConfigurationsWithResponse request returning *GetAgentConfigurationsResponse +func (c *ClientWithResponses) GetAgentConfigurationsWithResponse(ctx context.Context, params *GetAgentConfigurationsParams, reqEditors ...RequestEditorFn) (*GetAgentConfigurationsResponse, error) { + rsp, err := c.GetAgentConfigurations(ctx, params, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetAgentConfigurationsResponse(rsp) +} + +// CreateUpdateAgentConfigurationWithBodyWithResponse request with arbitrary body returning *CreateUpdateAgentConfigurationResponse +func (c *ClientWithResponses) CreateUpdateAgentConfigurationWithBodyWithResponse(ctx context.Context, params *CreateUpdateAgentConfigurationParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateUpdateAgentConfigurationResponse, error) { + rsp, err := c.CreateUpdateAgentConfigurationWithBody(ctx, params, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseCreateUpdateAgentConfigurationResponse(rsp) +} + +func (c *ClientWithResponses) CreateUpdateAgentConfigurationWithResponse(ctx context.Context, params *CreateUpdateAgentConfigurationParams, body CreateUpdateAgentConfigurationJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateUpdateAgentConfigurationResponse, error) { + rsp, err := c.CreateUpdateAgentConfiguration(ctx, params, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseCreateUpdateAgentConfigurationResponse(rsp) +} + // GetFleetAgentPoliciesWithResponse request returning *GetFleetAgentPoliciesResponse func (c *ClientWithResponses) GetFleetAgentPoliciesWithResponse(ctx context.Context, params *GetFleetAgentPoliciesParams, reqEditors ...RequestEditorFn) (*GetFleetAgentPoliciesResponse, error) { rsp, err := c.GetFleetAgentPolicies(ctx, params, reqEditors...) @@ -18787,6 +19325,161 @@ func (c *ClientWithResponses) UpdateDataViewDefaultWithResponse(ctx context.Cont return ParseUpdateDataViewDefaultResponse(rsp) } +// ParseDeleteAgentConfigurationResponse parses an HTTP response from a DeleteAgentConfigurationWithResponse call +func ParseDeleteAgentConfigurationResponse(rsp *http.Response) (*DeleteAgentConfigurationResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &DeleteAgentConfigurationResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest APMUIDeleteAgentConfigurationsResponse + 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 APMUI400Response + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest APMUI401Response + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest APMUI403Response + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest APMUI404Response + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + } + + return response, nil +} + +// ParseGetAgentConfigurationsResponse parses an HTTP response from a GetAgentConfigurationsWithResponse call +func ParseGetAgentConfigurationsResponse(rsp *http.Response) (*GetAgentConfigurationsResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetAgentConfigurationsResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest APMUIAgentConfigurationsResponse + 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 APMUI400Response + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest APMUI401Response + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest APMUI404Response + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + } + + return response, nil +} + +// ParseCreateUpdateAgentConfigurationResponse parses an HTTP response from a CreateUpdateAgentConfigurationWithResponse call +func ParseCreateUpdateAgentConfigurationResponse(rsp *http.Response) (*CreateUpdateAgentConfigurationResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &CreateUpdateAgentConfigurationResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest map[string]interface{} + 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 APMUI400Response + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest APMUI401Response + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest APMUI403Response + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest APMUI404Response + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + } + + return response, nil +} + // ParseGetFleetAgentPoliciesResponse parses an HTTP response from a GetFleetAgentPoliciesWithResponse call func ParseGetFleetAgentPoliciesResponse(rsp *http.Response) (*GetFleetAgentPoliciesResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) diff --git a/generated/kbapi/transform_schema.go b/generated/kbapi/transform_schema.go index 130f45f0a..11453eb8a 100644 --- a/generated/kbapi/transform_schema.go +++ b/generated/kbapi/transform_schema.go @@ -570,6 +570,7 @@ func transformFilterPaths(schema *Schema) { "/api/fleet/package_policies/{packagePolicyId}": {"get", "put", "delete"}, "/api/synthetics/params": {"post"}, "/api/synthetics/params/{id}": {"get", "put", "delete"}, + "/api/apm/settings/agent-configuration": {"get", "put", "delete"}, } for path, pathInfo := range schema.Paths { From 6dda03166d1e5671f5d0906a5686a8d68f060d06 Mon Sep 17 00:00:00 2001 From: Toby Brain Date: Mon, 7 Jul 2025 09:50:33 +1000 Subject: [PATCH 02/11] Add agent configuration resource --- internal/apm/agent_configuration/create.go | 57 ++++++++++++ internal/apm/agent_configuration/delete.go | 68 ++++++++++++++ internal/apm/agent_configuration/models.go | 27 ++++++ internal/apm/agent_configuration/read.go | 89 +++++++++++++++++++ internal/apm/agent_configuration/resource.go | 29 ++++++ .../apm/agent_configuration/resource_test.go | 77 ++++++++++++++++ internal/apm/agent_configuration/schema.go | 44 +++++++++ internal/apm/agent_configuration/update.go | 61 +++++++++++++ provider/plugin_framework.go | 2 + 9 files changed, 454 insertions(+) create mode 100644 internal/apm/agent_configuration/create.go create mode 100644 internal/apm/agent_configuration/delete.go create mode 100644 internal/apm/agent_configuration/models.go create mode 100644 internal/apm/agent_configuration/read.go create mode 100644 internal/apm/agent_configuration/resource.go create mode 100644 internal/apm/agent_configuration/resource_test.go create mode 100644 internal/apm/agent_configuration/schema.go create mode 100644 internal/apm/agent_configuration/update.go diff --git a/internal/apm/agent_configuration/create.go b/internal/apm/agent_configuration/create.go new file mode 100644 index 000000000..a036757e8 --- /dev/null +++ b/internal/apm/agent_configuration/create.go @@ -0,0 +1,57 @@ +package agent_configuration + +import ( + "context" + "fmt" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/elastic/terraform-provider-elasticstack/internal/utils" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-log/tflog" +) + +func (r *resourceAgentConfiguration) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan AgentConfiguration + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + kibana, err := r.client.GetKibanaOapiClient() + if err != nil { + resp.Diagnostics.AddError("Unable to get Kibana client", err.Error()) + return + } + + settings := make(map[string]string) + resp.Diagnostics.Append(plan.Settings.ElementsAs(ctx, &settings, false)...) + if resp.Diagnostics.HasError() { + return + } + + agentConfig := kbapi.CreateUpdateAgentConfigurationJSONRequestBody{ + AgentName: plan.AgentName.ValueStringPointer(), + Service: kbapi.APMUIServiceObject{ + Name: plan.ServiceName.ValueStringPointer(), + Environment: plan.ServiceEnvironment.ValueStringPointer(), + }, + Settings: settings, + } + + apiResp, err := kibana.API.CreateUpdateAgentConfiguration(ctx, &kbapi.CreateUpdateAgentConfigurationParams{}, agentConfig) + if err != nil { + resp.Diagnostics.AddError("Failed to create APM agent configuration", err.Error()) + return + } + defer apiResp.Body.Close() + + if diags := utils.CheckHttpErrorFromFW(apiResp, "Failed to create APM agent configuration"); diags.HasError() { + resp.Diagnostics.Append(diags...) + return + } + + id := plan.SetIDFromService() + tflog.Trace(ctx, fmt.Sprintf("Created APM agent configuration with ID: %s", id)) + + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} diff --git a/internal/apm/agent_configuration/delete.go b/internal/apm/agent_configuration/delete.go new file mode 100644 index 000000000..bd4cb9556 --- /dev/null +++ b/internal/apm/agent_configuration/delete.go @@ -0,0 +1,68 @@ +package agent_configuration + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "strings" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/elastic/terraform-provider-elasticstack/internal/utils" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-log/tflog" +) + +type deleteAgentConfigurationRequestBody struct { + Service struct { + Name string `json:"name"` + Environment *string `json:"environment,omitempty"` + } `json:"service"` +} + +func (r *resourceAgentConfiguration) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state AgentConfiguration + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + kibana, err := r.client.GetKibanaOapiClient() + if err != nil { + resp.Diagnostics.AddError("Unable to get Kibana client", err.Error()) + return + } + + idParts := strings.Split(state.ID.ValueString(), ":") + serviceName := idParts[0] + var serviceEnv *string + if len(idParts) > 1 { + serviceEnv = &idParts[1] + } + + deleteReqBody := deleteAgentConfigurationRequestBody{} + deleteReqBody.Service.Name = serviceName + deleteReqBody.Service.Environment = serviceEnv + + bodyBytes, err := json.Marshal(deleteReqBody) + if err != nil { + resp.Diagnostics.AddError("Failed to serialize delete request body", err.Error()) + return + } + + apiResp, err := kibana.API.DeleteAgentConfigurationWithBody(ctx, &kbapi.DeleteAgentConfigurationParams{}, "application/json", bytes.NewReader(bodyBytes)) + if err != nil { + resp.Diagnostics.AddError("Failed to delete APM agent configuration", err.Error()) + return + } + defer apiResp.Body.Close() + + if diags := utils.CheckHttpErrorFromFW(apiResp, "Failed to delete APM agent configuration"); diags.HasError() { + resp.Diagnostics.Append(diags...) + return + } + + tflog.Trace(ctx, fmt.Sprintf("Deleted APM agent configuration with ID: %s", state.ID.ValueString())) + + resp.State.RemoveResource(ctx) +} diff --git a/internal/apm/agent_configuration/models.go b/internal/apm/agent_configuration/models.go new file mode 100644 index 000000000..3bbaf1950 --- /dev/null +++ b/internal/apm/agent_configuration/models.go @@ -0,0 +1,27 @@ +package agent_configuration + +import ( + "strings" + + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// AgentConfiguration holds the agent configuration. +type AgentConfiguration struct { + ID types.String `tfsdk:"id"` + ServiceName types.String `tfsdk:"service_name"` + ServiceEnvironment types.String `tfsdk:"service_environment"` + AgentName types.String `tfsdk:"agent_name"` + Settings types.Map `tfsdk:"settings"` +} + +func (ac *AgentConfiguration) SetIDFromService() string { + parts := []string{ac.ServiceName.ValueString()} + if !ac.ServiceEnvironment.IsNull() && !ac.ServiceEnvironment.IsUnknown() && ac.ServiceEnvironment.ValueString() != "" { + parts = append(parts, ac.ServiceEnvironment.ValueString()) + } + + id := strings.Join(parts, ":") + ac.ID = types.StringValue(id) + return id +} diff --git a/internal/apm/agent_configuration/read.go b/internal/apm/agent_configuration/read.go new file mode 100644 index 000000000..6e800ef68 --- /dev/null +++ b/internal/apm/agent_configuration/read.go @@ -0,0 +1,89 @@ +package agent_configuration + +import ( + "context" + "fmt" + "strings" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/elastic/terraform-provider-elasticstack/internal/utils" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +func (r *resourceAgentConfiguration) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state AgentConfiguration + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + kibana, err := r.client.GetKibanaOapiClient() + if err != nil { + resp.Diagnostics.AddError("Unable to get Kibana client", err.Error()) + return + } + + apiResp, err := kibana.API.GetAgentConfigurationsWithResponse(ctx, &kbapi.GetAgentConfigurationsParams{}) + if err != nil { + resp.Diagnostics.AddError("Failed to get APM agent configurations", err.Error()) + return + } + + if diags := utils.CheckHttpErrorFromFW(apiResp.HTTPResponse, "Failed to get APM agent configurations"); diags.HasError() { + resp.Diagnostics.Append(diags...) + return + } + + if apiResp.JSON200 == nil { + resp.Diagnostics.AddError("Failed to get APM agent configurations from body", "Expected 200 response body to not be nil") + return + } + + idFromState := state.ID.ValueString() + var foundConfig *kbapi.APMUIAgentConfigurationObject + for _, config := range *apiResp.JSON200.Configurations { + if config.Service.Name == nil { + continue + } + idFromAPI := createAgentConfigIDfromAPI(config) + if idFromAPI == idFromState { + foundConfig = &config + break + } + } + + if foundConfig == nil { + resp.State.RemoveResource(ctx) + return + } + + state.ID = types.StringValue(idFromState) + state.ServiceName = types.StringPointerValue(foundConfig.Service.Name) + state.ServiceEnvironment = types.StringPointerValue(foundConfig.Service.Environment) + state.AgentName = types.StringPointerValue(foundConfig.AgentName) + + stringSettings := make(map[string]interface{}) + if foundConfig.Settings != nil { + for k, v := range foundConfig.Settings { + stringSettings[k] = fmt.Sprintf("%v", v) + } + } + + settings, diags := types.MapValueFrom(ctx, types.StringType, stringSettings) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + state.Settings = settings + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func createAgentConfigIDfromAPI(config kbapi.APMUIAgentConfigurationObject) string { + parts := []string{*config.Service.Name} + if config.Service.Environment != nil && *config.Service.Environment != "" { + parts = append(parts, *config.Service.Environment) + } + return strings.Join(parts, ":") +} diff --git a/internal/apm/agent_configuration/resource.go b/internal/apm/agent_configuration/resource.go new file mode 100644 index 000000000..88163527e --- /dev/null +++ b/internal/apm/agent_configuration/resource.go @@ -0,0 +1,29 @@ +package agent_configuration + +import ( + "context" + + "github.com/elastic/terraform-provider-elasticstack/internal/clients" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +// Ensure provider defined types fully satisfy framework interfaces. +var _ resource.Resource = &resourceAgentConfiguration{} + +func NewAgentConfigurationResource() resource.Resource { + return &resourceAgentConfiguration{} +} + +type resourceAgentConfiguration struct { + client *clients.ApiClient +} + +func (r *resourceAgentConfiguration) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_apm_agent_configuration" +} + +func (r *resourceAgentConfiguration) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + client, diags := clients.ConvertProviderData(req.ProviderData) + resp.Diagnostics.Append(diags...) + r.client = client +} diff --git a/internal/apm/agent_configuration/resource_test.go b/internal/apm/agent_configuration/resource_test.go new file mode 100644 index 000000000..4f9e0a828 --- /dev/null +++ b/internal/apm/agent_configuration/resource_test.go @@ -0,0 +1,77 @@ +package agent_configuration_test + +import ( + "fmt" + "testing" + + "github.com/elastic/terraform-provider-elasticstack/internal/acctest" + tf_acctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccResourceAgentConfiguration(t *testing.T) { + serviceName := tf_acctest.RandStringFromCharSet(10, tf_acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ProtoV6ProviderFactories: acctest.Providers, + Steps: []resource.TestStep{ + { + Config: testAccResourceAgentConfigurationCreate(serviceName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_apm_agent_configuration.test_config", "service_name", serviceName), + resource.TestCheckResourceAttr("elasticstack_apm_agent_configuration.test_config", "service_environment", "production"), + resource.TestCheckResourceAttr("elasticstack_apm_agent_configuration.test_config", "agent_name", "go"), + resource.TestCheckResourceAttr("elasticstack_apm_agent_configuration.test_config", "settings.transaction_sample_rate", "0.5"), + resource.TestCheckResourceAttr("elasticstack_apm_agent_configuration.test_config", "settings.capture_body", "all"), + ), + }, + { + Config: testAccResourceAgentConfigurationUpdate(serviceName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_apm_agent_configuration.test_config", "service_name", serviceName), + resource.TestCheckResourceAttr("elasticstack_apm_agent_configuration.test_config", "service_environment", "production"), + resource.TestCheckResourceAttr("elasticstack_apm_agent_configuration.test_config", "agent_name", "java"), + resource.TestCheckResourceAttr("elasticstack_apm_agent_configuration.test_config", "settings.transaction_sample_rate", "0.8"), + resource.TestCheckResourceAttr("elasticstack_apm_agent_configuration.test_config", "settings.capture_body", "off"), + ), + }, + }, + }) +} + +func testAccResourceAgentConfigurationCreate(serviceName string) string { + return fmt.Sprintf(` + provider "elasticstack" { + kibana {} + } + + resource "elasticstack_apm_agent_configuration" "test_config" { + service_name = "%s" + service_environment = "production" + agent_name = "go" + settings = { + "transaction_sample_rate" = "0.5" + "capture_body" = "all" + } + } + `, serviceName) +} + +func testAccResourceAgentConfigurationUpdate(serviceName string) string { + return fmt.Sprintf(` + provider "elasticstack" { + kibana {} + } + + resource "elasticstack_apm_agent_configuration" "test_config" { + service_name = "%s" + service_environment = "production" + agent_name = "java" + settings = { + "transaction_sample_rate" = "0.8" + "capture_body" = "off" + } + } + `, serviceName) +} diff --git a/internal/apm/agent_configuration/schema.go b/internal/apm/agent_configuration/schema.go new file mode 100644 index 000000000..f3d73269f --- /dev/null +++ b/internal/apm/agent_configuration/schema.go @@ -0,0 +1,44 @@ +package agent_configuration + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +func (r *resourceAgentConfiguration) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Manages APM agent configuration.", + + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "Internal identifier of the resource.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "service_name": schema.StringAttribute{ + Description: "The name of the service.", + Required: true, + }, + "service_environment": schema.StringAttribute{ + Description: "The environment of the service.", + Optional: true, + }, + "agent_name": schema.StringAttribute{ + Description: "The agent name is used by the UI to determine which settings to display.", + Optional: true, + }, + "settings": schema.MapAttribute{ + Description: "Agent configuration settings.", + Required: true, + ElementType: types.StringType, + }, + }, + } +} diff --git a/internal/apm/agent_configuration/update.go b/internal/apm/agent_configuration/update.go new file mode 100644 index 000000000..094f5d021 --- /dev/null +++ b/internal/apm/agent_configuration/update.go @@ -0,0 +1,61 @@ +package agent_configuration + +import ( + "context" + "fmt" + + "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" + "github.com/elastic/terraform-provider-elasticstack/internal/utils" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-log/tflog" +) + +func (r *resourceAgentConfiguration) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan AgentConfiguration + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + kibana, err := r.client.GetKibanaOapiClient() + if err != nil { + resp.Diagnostics.AddError("Unable to get Kibana client", err.Error()) + return + } + + settings := make(map[string]string) + resp.Diagnostics.Append(plan.Settings.ElementsAs(ctx, &settings, false)...) + if resp.Diagnostics.HasError() { + return + } + + agentConfig := kbapi.CreateUpdateAgentConfigurationJSONRequestBody{ + AgentName: plan.AgentName.ValueStringPointer(), + Service: kbapi.APMUIServiceObject{ + Name: plan.ServiceName.ValueStringPointer(), + Environment: plan.ServiceEnvironment.ValueStringPointer(), + }, + Settings: settings, + } + + overwrite := true + params := &kbapi.CreateUpdateAgentConfigurationParams{ + Overwrite: &overwrite, + } + + apiResp, err := kibana.API.CreateUpdateAgentConfiguration(ctx, params, agentConfig) + if err != nil { + resp.Diagnostics.AddError("Failed to update APM agent configuration", err.Error()) + return + } + defer apiResp.Body.Close() + + if diags := utils.CheckHttpErrorFromFW(apiResp, "Failed to update APM agent configuration"); diags.HasError() { + resp.Diagnostics.Append(diags...) + return + } + + tflog.Trace(ctx, fmt.Sprintf("Updated APM agent configuration with ID: %s", plan.ID.ValueString())) + + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} diff --git a/provider/plugin_framework.go b/provider/plugin_framework.go index fcc31bfe6..1da87c988 100644 --- a/provider/plugin_framework.go +++ b/provider/plugin_framework.go @@ -3,6 +3,7 @@ package provider import ( "context" + "github.com/elastic/terraform-provider-elasticstack/internal/apm/agent_configuration" "github.com/elastic/terraform-provider-elasticstack/internal/clients" "github.com/elastic/terraform-provider-elasticstack/internal/clients/config" "github.com/elastic/terraform-provider-elasticstack/internal/elasticsearch/index/data_stream_lifecycle" @@ -90,6 +91,7 @@ func (p *Provider) DataSources(ctx context.Context) []func() datasource.DataSour func (p *Provider) Resources(ctx context.Context) []func() resource.Resource { return []func() resource.Resource{ + agent_configuration.NewAgentConfigurationResource, func() resource.Resource { return &import_saved_objects.Resource{} }, data_view.NewResource, func() resource.Resource { return ¶meter.Resource{} }, From 57eb439737f08af1cfac1121c1d5421d60fad6eb Mon Sep 17 00:00:00 2001 From: Toby Brain Date: Mon, 7 Jul 2025 09:50:48 +1000 Subject: [PATCH 03/11] Add windsurf rules --- .windsurf/rules | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .windsurf/rules diff --git a/.windsurf/rules b/.windsurf/rules new file mode 100644 index 000000000..f10e9e643 --- /dev/null +++ b/.windsurf/rules @@ -0,0 +1,9 @@ +* The project is a Terraform provider, written in Golang +* The provider manages Elastic Stack resources +* There is a mix of SDK, and plugin framework resources +* New resources should be written with the Terraform plugin framework +* Plugin framework resources should: + * Follow the example set in /internal/elasticsearch/security/system_user + * Be contained within their own module + * Have the main concepts split across their own files + * Include acceptance tests From 0359a86897cbb253f3ef3f22e34d1af7206965e7 Mon Sep 17 00:00:00 2001 From: Toby Brain Date: Mon, 7 Jul 2025 10:49:33 +1000 Subject: [PATCH 04/11] make docs-generate --- docs/resources/apm_agent_configuration.md | 54 +++++++++++++++++++ .../import.sh | 1 + .../resource.tf | 13 +++++ internal/apm/agent_configuration/resource.go | 7 +++ .../resources/apm_agent_configuration.md.tmpl | 23 ++++++++ 5 files changed, 98 insertions(+) create mode 100644 docs/resources/apm_agent_configuration.md create mode 100644 examples/resources/elasticstack_apm_agent_configuration/import.sh create mode 100644 examples/resources/elasticstack_apm_agent_configuration/resource.tf create mode 100644 templates/resources/apm_agent_configuration.md.tmpl diff --git a/docs/resources/apm_agent_configuration.md b/docs/resources/apm_agent_configuration.md new file mode 100644 index 000000000..ff26c0665 --- /dev/null +++ b/docs/resources/apm_agent_configuration.md @@ -0,0 +1,54 @@ +--- +subcategory: "Kibana" +layout: "" +page_title: "Elasticstack: elasticstack_apm_agent_configuration Resource" +description: |- + Creates or updates an APM agent configuration +--- + +# Resource: elasticstack_apm_agent_configuration + +Creates or updates a an APM agent configuration. See https://www.elastic.co/docs/solutions/observability/apm/apm-agent-central-configuration + +## Example Usage + +```terraform +provider "elasticstack" { + elasticsearch {} +} + +resource "elasticstack_apm_agent_configuration" "test_config" { + service_name = "my-service" + service_environment = "production" + agent_name = "go" + settings = { + "transaction_sample_rate" = "0.5" + "capture_body" = "all" + } +} +``` + + +## Schema + +### Required + +- `service_name` (String) The name of the service. +- `settings` (Map of String) Agent configuration settings. + +### Optional + +- `agent_name` (String) The agent name is used by the UI to determine which settings to display. +- `service_environment` (String) The environment of the service. + +### Read-Only + +- `id` (String) Internal identifier of the resource. + +## Import + +Import is supported using the following syntax: + +```shell +terraform import elasticstack_apm_agent_configuration.test_configuration my-service:production +``` diff --git a/examples/resources/elasticstack_apm_agent_configuration/import.sh b/examples/resources/elasticstack_apm_agent_configuration/import.sh new file mode 100644 index 000000000..495c00058 --- /dev/null +++ b/examples/resources/elasticstack_apm_agent_configuration/import.sh @@ -0,0 +1 @@ +terraform import elasticstack_apm_agent_configuration.test_configuration my-service:production diff --git a/examples/resources/elasticstack_apm_agent_configuration/resource.tf b/examples/resources/elasticstack_apm_agent_configuration/resource.tf new file mode 100644 index 000000000..9c9e5d9ce --- /dev/null +++ b/examples/resources/elasticstack_apm_agent_configuration/resource.tf @@ -0,0 +1,13 @@ +provider "elasticstack" { + elasticsearch {} +} + +resource "elasticstack_apm_agent_configuration" "test_config" { + service_name = "my-service" + service_environment = "production" + agent_name = "go" + settings = { + "transaction_sample_rate" = "0.5" + "capture_body" = "all" + } +} diff --git a/internal/apm/agent_configuration/resource.go b/internal/apm/agent_configuration/resource.go index 88163527e..ee609ab1e 100644 --- a/internal/apm/agent_configuration/resource.go +++ b/internal/apm/agent_configuration/resource.go @@ -4,11 +4,14 @@ import ( "context" "github.com/elastic/terraform-provider-elasticstack/internal/clients" + "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" ) // Ensure provider defined types fully satisfy framework interfaces. var _ resource.Resource = &resourceAgentConfiguration{} +var _ resource.ResourceWithConfigure = &resourceAgentConfiguration{} +var _ resource.ResourceWithImportState = &resourceAgentConfiguration{} func NewAgentConfigurationResource() resource.Resource { return &resourceAgentConfiguration{} @@ -27,3 +30,7 @@ func (r *resourceAgentConfiguration) Configure(ctx context.Context, req resource resp.Diagnostics.Append(diags...) r.client = client } + +func (r *resourceAgentConfiguration) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), request, response) +} diff --git a/templates/resources/apm_agent_configuration.md.tmpl b/templates/resources/apm_agent_configuration.md.tmpl new file mode 100644 index 000000000..f489a472f --- /dev/null +++ b/templates/resources/apm_agent_configuration.md.tmpl @@ -0,0 +1,23 @@ +--- +subcategory: "Kibana" +layout: "" +page_title: "Elasticstack: elasticstack_apm_agent_configuration Resource" +description: |- + Creates or updates an APM agent configuration +--- + +# Resource: elasticstack_apm_agent_configuration + +Creates or updates a an APM agent configuration. See https://www.elastic.co/docs/solutions/observability/apm/apm-agent-central-configuration + +## Example Usage + +{{ tffile "examples/resources/elasticstack_apm_agent_configuration/resource.tf" }} + +{{ .SchemaMarkdown | trimspace }} + +## Import + +Import is supported using the following syntax: + +{{ codefile "shell" "examples/resources/elasticstack_apm_agent_configuration/import.sh" }} From 10cd43e22c6de6f45ebda619ea9f428fc8b90bab Mon Sep 17 00:00:00 2001 From: Toby Brain Date: Mon, 7 Jul 2025 14:04:38 +1000 Subject: [PATCH 05/11] Patch delete agent policy spec --- generated/kbapi/kibana.gen.go | 8 ++++++- generated/kbapi/transform_schema.go | 12 +++++++++++ internal/apm/agent_configuration/delete.go | 25 ++++++---------------- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/generated/kbapi/kibana.gen.go b/generated/kbapi/kibana.gen.go index 750c00590..25666fcca 100644 --- a/generated/kbapi/kibana.gen.go +++ b/generated/kbapi/kibana.gen.go @@ -693,6 +693,12 @@ type APMUIDeleteAgentConfigurationsResponse struct { Result *string `json:"result,omitempty"` } +// APMUIDeleteServiceObject defines model for APM_UI_delete_service_object. +type APMUIDeleteServiceObject struct { + // Service Service + Service *APMUIServiceObject `json:"service,omitempty"` +} + // APMUIServiceObject Service type APMUIServiceObject struct { // Environment The environment of the service. @@ -3528,7 +3534,7 @@ type PutParameterJSONBody struct { } // DeleteAgentConfigurationJSONRequestBody defines body for DeleteAgentConfiguration for application/json ContentType. -type DeleteAgentConfigurationJSONRequestBody = APMUIServiceObject +type DeleteAgentConfigurationJSONRequestBody = APMUIDeleteServiceObject // CreateUpdateAgentConfigurationJSONRequestBody defines body for CreateUpdateAgentConfiguration for application/json ContentType. type CreateUpdateAgentConfigurationJSONRequestBody = APMUIAgentConfigurationIntakeObject diff --git a/generated/kbapi/transform_schema.go b/generated/kbapi/transform_schema.go index 11453eb8a..76cee7544 100644 --- a/generated/kbapi/transform_schema.go +++ b/generated/kbapi/transform_schema.go @@ -820,6 +820,18 @@ func transformKibanaPaths(schema *Schema) { schema.Components.CreateRef(schema, "Data_views_create_data_view_request_object_inner", "schemas.Data_views_create_data_view_request_object.properties.data_view") schema.Components.CreateRef(schema, "Data_views_update_data_view_request_object_inner", "schemas.Data_views_update_data_view_request_object.properties.data_view") + + // Can be removed when https://github.com/elastic/kibana/pull/226713 is merged + schema.Components.Set("schemas.APM_UI_delete_service_object", Map{ + "type": "object", + "properties": Map{ + "service": Map{ + "$ref": "#/components/schemas/APM_UI_service_object", + }, + }, + }) + agentConfigPath := schema.MustGetPath("/api/apm/settings/agent-configuration") + agentConfigPath.Delete.Set("requestBody.content.application/json.schema.$ref", "#/components/schemas/APM_UI_delete_service_object") } // transformFleetPaths fixes the fleet paths. diff --git a/internal/apm/agent_configuration/delete.go b/internal/apm/agent_configuration/delete.go index bd4cb9556..a0c8fd494 100644 --- a/internal/apm/agent_configuration/delete.go +++ b/internal/apm/agent_configuration/delete.go @@ -1,9 +1,7 @@ package agent_configuration import ( - "bytes" "context" - "encoding/json" "fmt" "strings" @@ -13,13 +11,6 @@ import ( "github.com/hashicorp/terraform-plugin-log/tflog" ) -type deleteAgentConfigurationRequestBody struct { - Service struct { - Name string `json:"name"` - Environment *string `json:"environment,omitempty"` - } `json:"service"` -} - func (r *resourceAgentConfiguration) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { var state AgentConfiguration resp.Diagnostics.Append(req.State.Get(ctx, &state)...) @@ -40,17 +31,13 @@ func (r *resourceAgentConfiguration) Delete(ctx context.Context, req resource.De serviceEnv = &idParts[1] } - deleteReqBody := deleteAgentConfigurationRequestBody{} - deleteReqBody.Service.Name = serviceName - deleteReqBody.Service.Environment = serviceEnv - - bodyBytes, err := json.Marshal(deleteReqBody) - if err != nil { - resp.Diagnostics.AddError("Failed to serialize delete request body", err.Error()) - return + deleteReqBody := kbapi.APMUIDeleteServiceObject{ + Service: &kbapi.APMUIServiceObject{ + Name: &serviceName, + Environment: serviceEnv, + }, } - - apiResp, err := kibana.API.DeleteAgentConfigurationWithBody(ctx, &kbapi.DeleteAgentConfigurationParams{}, "application/json", bytes.NewReader(bodyBytes)) + apiResp, err := kibana.API.DeleteAgentConfiguration(ctx, &kbapi.DeleteAgentConfigurationParams{}, deleteReqBody) if err != nil { resp.Diagnostics.AddError("Failed to delete APM agent configuration", err.Error()) return From e8192142ed82341f2adf60150d5f2bbe8afe624a Mon Sep 17 00:00:00 2001 From: Toby Brain Date: Tue, 8 Jul 2025 20:55:37 +1000 Subject: [PATCH 06/11] Set Elastic API version --- internal/apm/agent_configuration/create.go | 10 +++++++++- internal/apm/agent_configuration/delete.go | 8 +++++++- internal/apm/agent_configuration/read.go | 7 ++++++- internal/apm/agent_configuration/update.go | 3 ++- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/internal/apm/agent_configuration/create.go b/internal/apm/agent_configuration/create.go index a036757e8..b1b36003c 100644 --- a/internal/apm/agent_configuration/create.go +++ b/internal/apm/agent_configuration/create.go @@ -10,6 +10,8 @@ import ( "github.com/hashicorp/terraform-plugin-log/tflog" ) +const elasticAPIVersion = "2023-10-31" + func (r *resourceAgentConfiguration) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var plan AgentConfiguration resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) @@ -38,7 +40,13 @@ func (r *resourceAgentConfiguration) Create(ctx context.Context, req resource.Cr Settings: settings, } - apiResp, err := kibana.API.CreateUpdateAgentConfiguration(ctx, &kbapi.CreateUpdateAgentConfigurationParams{}, agentConfig) + apiResp, err := kibana.API.CreateUpdateAgentConfiguration( + ctx, + &kbapi.CreateUpdateAgentConfigurationParams{ + ElasticApiVersion: elasticAPIVersion, + }, + agentConfig, + ) if err != nil { resp.Diagnostics.AddError("Failed to create APM agent configuration", err.Error()) return diff --git a/internal/apm/agent_configuration/delete.go b/internal/apm/agent_configuration/delete.go index a0c8fd494..3e120c756 100644 --- a/internal/apm/agent_configuration/delete.go +++ b/internal/apm/agent_configuration/delete.go @@ -37,7 +37,13 @@ func (r *resourceAgentConfiguration) Delete(ctx context.Context, req resource.De Environment: serviceEnv, }, } - apiResp, err := kibana.API.DeleteAgentConfiguration(ctx, &kbapi.DeleteAgentConfigurationParams{}, deleteReqBody) + apiResp, err := kibana.API.DeleteAgentConfiguration( + ctx, + &kbapi.DeleteAgentConfigurationParams{ + ElasticApiVersion: elasticAPIVersion, + }, + deleteReqBody, + ) if err != nil { resp.Diagnostics.AddError("Failed to delete APM agent configuration", err.Error()) return diff --git a/internal/apm/agent_configuration/read.go b/internal/apm/agent_configuration/read.go index 6e800ef68..67eeb6658 100644 --- a/internal/apm/agent_configuration/read.go +++ b/internal/apm/agent_configuration/read.go @@ -24,7 +24,12 @@ func (r *resourceAgentConfiguration) Read(ctx context.Context, req resource.Read return } - apiResp, err := kibana.API.GetAgentConfigurationsWithResponse(ctx, &kbapi.GetAgentConfigurationsParams{}) + apiResp, err := kibana.API.GetAgentConfigurationsWithResponse( + ctx, + &kbapi.GetAgentConfigurationsParams{ + ElasticApiVersion: elasticAPIVersion, + }, + ) if err != nil { resp.Diagnostics.AddError("Failed to get APM agent configurations", err.Error()) return diff --git a/internal/apm/agent_configuration/update.go b/internal/apm/agent_configuration/update.go index 094f5d021..13626f3b1 100644 --- a/internal/apm/agent_configuration/update.go +++ b/internal/apm/agent_configuration/update.go @@ -40,7 +40,8 @@ func (r *resourceAgentConfiguration) Update(ctx context.Context, req resource.Up overwrite := true params := &kbapi.CreateUpdateAgentConfigurationParams{ - Overwrite: &overwrite, + Overwrite: &overwrite, + ElasticApiVersion: elasticAPIVersion, } apiResp, err := kibana.API.CreateUpdateAgentConfiguration(ctx, params, agentConfig) From bc4e8c24bd83eb4ec27b4da3715ec1496ba4a5c0 Mon Sep 17 00:00:00 2001 From: Toby Brain Date: Wed, 9 Jul 2025 22:18:09 +1000 Subject: [PATCH 07/11] Changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 284554342..cff0be8e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ## [Unreleased] +- Add `elasticstack_apm_agent_configuration` resource ([#1196](https://github.com/elastic/terraform-provider-elasticstack/pull/1196)) + ## [0.11.16] - 2025-07-09 - Add `headers` for the provider connection ([#1057](https://github.com/elastic/terraform-provider-elasticstack/pull/1057)) From 69a240d7363c13140ed66db3dac036efa64d1dbd Mon Sep 17 00:00:00 2001 From: Toby Brain Date: Fri, 18 Jul 2025 20:59:34 +1000 Subject: [PATCH 08/11] Apply suggestions from code review Co-authored-by: Dmitry Onishchenko <8962171+dimuon@users.noreply.github.com> --- docs/resources/apm_agent_configuration.md | 2 +- internal/apm/agent_configuration/read.go | 2 +- templates/resources/apm_agent_configuration.md.tmpl | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/resources/apm_agent_configuration.md b/docs/resources/apm_agent_configuration.md index ff26c0665..8df89ceae 100644 --- a/docs/resources/apm_agent_configuration.md +++ b/docs/resources/apm_agent_configuration.md @@ -8,7 +8,7 @@ description: |- # Resource: elasticstack_apm_agent_configuration -Creates or updates a an APM agent configuration. See https://www.elastic.co/docs/solutions/observability/apm/apm-agent-central-configuration +Creates or updates an APM agent configuration. See https://www.elastic.co/docs/solutions/observability/apm/apm-agent-central-configuration ## Example Usage diff --git a/internal/apm/agent_configuration/read.go b/internal/apm/agent_configuration/read.go index 67eeb6658..334d45ce5 100644 --- a/internal/apm/agent_configuration/read.go +++ b/internal/apm/agent_configuration/read.go @@ -34,7 +34,7 @@ func (r *resourceAgentConfiguration) Read(ctx context.Context, req resource.Read resp.Diagnostics.AddError("Failed to get APM agent configurations", err.Error()) return } - + defer apiResp.Body.Close() if diags := utils.CheckHttpErrorFromFW(apiResp.HTTPResponse, "Failed to get APM agent configurations"); diags.HasError() { resp.Diagnostics.Append(diags...) return diff --git a/templates/resources/apm_agent_configuration.md.tmpl b/templates/resources/apm_agent_configuration.md.tmpl index f489a472f..103e4b62e 100644 --- a/templates/resources/apm_agent_configuration.md.tmpl +++ b/templates/resources/apm_agent_configuration.md.tmpl @@ -8,7 +8,7 @@ description: |- # Resource: elasticstack_apm_agent_configuration -Creates or updates a an APM agent configuration. See https://www.elastic.co/docs/solutions/observability/apm/apm-agent-central-configuration +Creates or updates an APM agent configuration. See https://www.elastic.co/docs/solutions/observability/apm/apm-agent-central-configuration ## Example Usage From 3e0f5706fcf6fff2188ca8891ba1cb462b2ba40d Mon Sep 17 00:00:00 2001 From: Toby Brain Date: Sat, 19 Jul 2025 07:39:45 +1000 Subject: [PATCH 09/11] Update internal/apm/agent_configuration/read.go Co-authored-by: Dmitry Onishchenko <8962171+dimuon@users.noreply.github.com> --- internal/apm/agent_configuration/read.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/apm/agent_configuration/read.go b/internal/apm/agent_configuration/read.go index 334d45ce5..610a21e4c 100644 --- a/internal/apm/agent_configuration/read.go +++ b/internal/apm/agent_configuration/read.go @@ -34,7 +34,6 @@ func (r *resourceAgentConfiguration) Read(ctx context.Context, req resource.Read resp.Diagnostics.AddError("Failed to get APM agent configurations", err.Error()) return } - defer apiResp.Body.Close() if diags := utils.CheckHttpErrorFromFW(apiResp.HTTPResponse, "Failed to get APM agent configurations"); diags.HasError() { resp.Diagnostics.Append(diags...) return From 528f118c98f5917831769e7ece2f39112b919a5b Mon Sep 17 00:00:00 2001 From: Toby Brain Date: Sun, 20 Jul 2025 07:23:38 +1000 Subject: [PATCH 10/11] PR feedback --- internal/apm/agent_configuration/create.go | 12 ++++-- internal/apm/agent_configuration/delete.go | 2 - internal/apm/agent_configuration/read.go | 50 +++++++++++++++------- internal/apm/agent_configuration/update.go | 9 +++- 4 files changed, 50 insertions(+), 23 deletions(-) diff --git a/internal/apm/agent_configuration/create.go b/internal/apm/agent_configuration/create.go index b1b36003c..561ce0b05 100644 --- a/internal/apm/agent_configuration/create.go +++ b/internal/apm/agent_configuration/create.go @@ -58,8 +58,14 @@ func (r *resourceAgentConfiguration) Create(ctx context.Context, req resource.Cr return } - id := plan.SetIDFromService() - tflog.Trace(ctx, fmt.Sprintf("Created APM agent configuration with ID: %s", id)) + plan.SetIDFromService() - resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) + updatedState, diags := r.read(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Trace(ctx, fmt.Sprintf("Created APM agent configuration with ID: %s", updatedState.ID.ValueString())) + resp.Diagnostics.Append(resp.State.Set(ctx, updatedState)...) } diff --git a/internal/apm/agent_configuration/delete.go b/internal/apm/agent_configuration/delete.go index 3e120c756..6077ba8c9 100644 --- a/internal/apm/agent_configuration/delete.go +++ b/internal/apm/agent_configuration/delete.go @@ -56,6 +56,4 @@ func (r *resourceAgentConfiguration) Delete(ctx context.Context, req resource.De } tflog.Trace(ctx, fmt.Sprintf("Deleted APM agent configuration with ID: %s", state.ID.ValueString())) - - resp.State.RemoveResource(ctx) } diff --git a/internal/apm/agent_configuration/read.go b/internal/apm/agent_configuration/read.go index 610a21e4c..5c81e60da 100644 --- a/internal/apm/agent_configuration/read.go +++ b/internal/apm/agent_configuration/read.go @@ -7,6 +7,7 @@ import ( "github.com/elastic/terraform-provider-elasticstack/generated/kbapi" "github.com/elastic/terraform-provider-elasticstack/internal/utils" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -18,10 +19,27 @@ func (r *resourceAgentConfiguration) Read(ctx context.Context, req resource.Read return } + updatedState, diags := r.read(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if updatedState == nil { + resp.State.RemoveResource(ctx) + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, updatedState)...) +} + +func (r *resourceAgentConfiguration) read(ctx context.Context, state *AgentConfiguration) (*AgentConfiguration, diag.Diagnostics) { + var diags diag.Diagnostics + kibana, err := r.client.GetKibanaOapiClient() if err != nil { - resp.Diagnostics.AddError("Unable to get Kibana client", err.Error()) - return + diags.AddError("Unable to get Kibana client", err.Error()) + return nil, diags } apiResp, err := kibana.API.GetAgentConfigurationsWithResponse( @@ -31,17 +49,18 @@ func (r *resourceAgentConfiguration) Read(ctx context.Context, req resource.Read }, ) if err != nil { - resp.Diagnostics.AddError("Failed to get APM agent configurations", err.Error()) - return + diags.AddError("Failed to get APM agent configurations", err.Error()) + return nil, diags } - if diags := utils.CheckHttpErrorFromFW(apiResp.HTTPResponse, "Failed to get APM agent configurations"); diags.HasError() { - resp.Diagnostics.Append(diags...) - return + + if httpDiags := utils.CheckHttpErrorFromFW(apiResp.HTTPResponse, "Failed to get APM agent configurations"); httpDiags.HasError() { + diags.Append(httpDiags...) + return nil, diags } if apiResp.JSON200 == nil { - resp.Diagnostics.AddError("Failed to get APM agent configurations from body", "Expected 200 response body to not be nil") - return + diags.AddError("Failed to get APM agent configurations from body", "Expected 200 response body to not be nil") + return nil, diags } idFromState := state.ID.ValueString() @@ -58,8 +77,7 @@ func (r *resourceAgentConfiguration) Read(ctx context.Context, req resource.Read } if foundConfig == nil { - resp.State.RemoveResource(ctx) - return + return nil, diags } state.ID = types.StringValue(idFromState) @@ -74,14 +92,14 @@ func (r *resourceAgentConfiguration) Read(ctx context.Context, req resource.Read } } - settings, diags := types.MapValueFrom(ctx, types.StringType, stringSettings) - resp.Diagnostics.Append(diags...) - if resp.Diagnostics.HasError() { - return + settings, mapDiags := types.MapValueFrom(ctx, types.StringType, stringSettings) + diags.Append(mapDiags...) + if diags.HasError() { + return nil, diags } state.Settings = settings - resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) + return state, diags } func createAgentConfigIDfromAPI(config kbapi.APMUIAgentConfigurationObject) string { diff --git a/internal/apm/agent_configuration/update.go b/internal/apm/agent_configuration/update.go index 13626f3b1..63f7c68c6 100644 --- a/internal/apm/agent_configuration/update.go +++ b/internal/apm/agent_configuration/update.go @@ -56,7 +56,12 @@ func (r *resourceAgentConfiguration) Update(ctx context.Context, req resource.Up return } - tflog.Trace(ctx, fmt.Sprintf("Updated APM agent configuration with ID: %s", plan.ID.ValueString())) + updatedState, diags := r.read(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } - resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) + tflog.Trace(ctx, fmt.Sprintf("Updated APM agent configuration with ID: %s", updatedState.ID.ValueString())) + resp.Diagnostics.Append(resp.State.Set(ctx, updatedState)...) } From ce7aefdc7f3215ece6fb6b1eb020e2d12af8afcd Mon Sep 17 00:00:00 2001 From: Toby Brain Date: Sun, 20 Jul 2025 09:43:28 +1000 Subject: [PATCH 11/11] Remove spec customisation The fix has been merged into Kibana/main --- generated/kbapi/kibana.gen.go | 4 ++-- generated/kbapi/transform_schema.go | 12 ------------ internal/apm/agent_configuration/delete.go | 2 +- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/generated/kbapi/kibana.gen.go b/generated/kbapi/kibana.gen.go index 25666fcca..52a36324e 100644 --- a/generated/kbapi/kibana.gen.go +++ b/generated/kbapi/kibana.gen.go @@ -693,10 +693,10 @@ type APMUIDeleteAgentConfigurationsResponse struct { Result *string `json:"result,omitempty"` } -// APMUIDeleteServiceObject defines model for APM_UI_delete_service_object. +// APMUIDeleteServiceObject Service type APMUIDeleteServiceObject struct { // Service Service - Service *APMUIServiceObject `json:"service,omitempty"` + Service APMUIServiceObject `json:"service"` } // APMUIServiceObject Service diff --git a/generated/kbapi/transform_schema.go b/generated/kbapi/transform_schema.go index 76cee7544..11453eb8a 100644 --- a/generated/kbapi/transform_schema.go +++ b/generated/kbapi/transform_schema.go @@ -820,18 +820,6 @@ func transformKibanaPaths(schema *Schema) { schema.Components.CreateRef(schema, "Data_views_create_data_view_request_object_inner", "schemas.Data_views_create_data_view_request_object.properties.data_view") schema.Components.CreateRef(schema, "Data_views_update_data_view_request_object_inner", "schemas.Data_views_update_data_view_request_object.properties.data_view") - - // Can be removed when https://github.com/elastic/kibana/pull/226713 is merged - schema.Components.Set("schemas.APM_UI_delete_service_object", Map{ - "type": "object", - "properties": Map{ - "service": Map{ - "$ref": "#/components/schemas/APM_UI_service_object", - }, - }, - }) - agentConfigPath := schema.MustGetPath("/api/apm/settings/agent-configuration") - agentConfigPath.Delete.Set("requestBody.content.application/json.schema.$ref", "#/components/schemas/APM_UI_delete_service_object") } // transformFleetPaths fixes the fleet paths. diff --git a/internal/apm/agent_configuration/delete.go b/internal/apm/agent_configuration/delete.go index 6077ba8c9..4b1d60432 100644 --- a/internal/apm/agent_configuration/delete.go +++ b/internal/apm/agent_configuration/delete.go @@ -32,7 +32,7 @@ func (r *resourceAgentConfiguration) Delete(ctx context.Context, req resource.De } deleteReqBody := kbapi.APMUIDeleteServiceObject{ - Service: &kbapi.APMUIServiceObject{ + Service: kbapi.APMUIServiceObject{ Name: &serviceName, Environment: serviceEnv, },