diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 06c1d69d1..12c95b77d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -97,6 +97,8 @@ jobs: - '8.5.3' - '8.6.2' - '8.7.0' + - '8.8.2' + - '8.9.2' steps: - uses: actions/checkout@v3 - uses: actions/setup-go@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index dcd805186..5e671257f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## [Unreleased] ### Added +- Add support for the `.slack_api` connector type for Kibana action connectors ([#419](https://github.com/elastic/terraform-provider-elasticstack/pull/419)) ## [0.7.0] - 2023-08-22 diff --git a/docs/resources/kibana_action_connector.md b/docs/resources/kibana_action_connector.md index e9b874e2e..a9706c462 100644 --- a/docs/resources/kibana_action_connector.md +++ b/docs/resources/kibana_action_connector.md @@ -44,6 +44,14 @@ resource "elasticstack_kibana_action_connector" "slack-connector" { webhookUrl = "" }) } + +resource "elasticstack_kibana_action_connector" "slack-api-connector" { + name = "slack" + connector_type_id = ".slack_api" + secrets = jsonencode({ + token = "" + }) +} ``` diff --git a/examples/resources/elasticstack_kibana_action_connector/resource.tf b/examples/resources/elasticstack_kibana_action_connector/resource.tf index c60efec16..9557c5113 100644 --- a/examples/resources/elasticstack_kibana_action_connector/resource.tf +++ b/examples/resources/elasticstack_kibana_action_connector/resource.tf @@ -29,3 +29,11 @@ resource "elasticstack_kibana_action_connector" "slack-connector" { webhookUrl = "" }) } + +resource "elasticstack_kibana_action_connector" "slack-api-connector" { + name = "slack" + connector_type_id = ".slack_api" + secrets = jsonencode({ + token = "" + }) +} diff --git a/generated/connectors/README.md b/generated/connectors/README.md index f17d53e42..94b8a4392 100644 --- a/generated/connectors/README.md +++ b/generated/connectors/README.md @@ -1,5 +1,7 @@ [OpenAPI specs](./bundled.yaml) is copied from [Kibana repo](https://raw.githubusercontent.com/elastic/kibana/8.7/x-pack/plugins/actions/docs/openapi/bundled.yaml) with some modifications: +- `.slack_api` connector support comes from version 8.8 of the API specification; +- added `.slack_api` as a possible value for `connector_types`; - added mapping section for discriminator field in `POST` `/s/{spaceId}/api/actions/connector`; - added explicit object definitions for `400`, `401` and `404` errors (`oapi-codegen` doesn't generate proper code for embedded anonymous objects in some cases) - `bad_request_error`, `authorization_error` and `object_not_found_error`; - added missing `oneOf` types in `requestBody` for `PUT` `/s/{spaceId}/api/actions/connector/{connectorId}` - the original `bundled.yaml` misses some connector types in the `PUT` `requestBody` defintion: @@ -7,6 +9,7 @@ - `update_connector_request_pagerduty`; - `update_connector_request_servicenow_sir`; - `update_connector_request_slack`; + - `update_connector_request_slack_api`; - `update_connector_request_teams`; - `update_connector_request_tines`; - `update_connector_request_webhook`; @@ -31,6 +34,7 @@ - `connector_response_properties_servicenow_itom`; - `connector_response_properties_servicenow_sir`; - `connector_response_properties_slack`; + - `connector_response_properties_slack_api`; - `connector_response_properties_swimlane`; - `connector_response_properties_teams`; - `connector_response_properties_tines`; diff --git a/generated/connectors/bundled.yaml b/generated/connectors/bundled.yaml index c5ec5a3bb..ce0dfa811 100644 --- a/generated/connectors/bundled.yaml +++ b/generated/connectors/bundled.yaml @@ -46,6 +46,7 @@ paths: - $ref: '#/components/schemas/create_connector_request_servicenow_itom' - $ref: '#/components/schemas/create_connector_request_servicenow_sir' - $ref: '#/components/schemas/create_connector_request_slack' + - $ref: '#/components/schemas/create_connector_request_slack_api' - $ref: '#/components/schemas/create_connector_request_swimlane' - $ref: '#/components/schemas/create_connector_request_teams' - $ref: '#/components/schemas/create_connector_request_tines' @@ -66,6 +67,7 @@ paths: .servicenow-itom: '#/components/schemas/create_connector_request_servicenow_itom' .servicenow-sir: '#/components/schemas/create_connector_request_servicenow_sir' .slack: '#/components/schemas/create_connector_request_slack' + .slack_api: '#/components/schemas/create_connector_request_slack_api' .swimlane: '#/components/schemas/create_connector_request_swimlane' .teams: '#/components/schemas/create_connector_request_teams' .tines: '#/components/schemas/create_connector_request_tines' @@ -214,6 +216,7 @@ paths: - $ref: '#/components/schemas/update_connector_request_servicenow_itom' - $ref: '#/components/schemas/update_connector_request_servicenow_sir' - $ref: '#/components/schemas/update_connector_request_slack' + - $ref: '#/components/schemas/update_connector_request_slack_api' - $ref: '#/components/schemas/update_connector_request_swimlane' - $ref: '#/components/schemas/update_connector_request_teams' - $ref: '#/components/schemas/update_connector_request_tines' @@ -1398,6 +1401,37 @@ components: example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_slack' + secrets_properties_slack_api: + title: Connector secrets properties for a Web API Slack connector + description: Defines secrets for connectors when type is `.slack`. + required: + - token + type: object + properties: + token: + type: string + description: Slack bot user OAuth token. + create_connector_request_slack_api: + title: Create Slack connector request + description: The Slack connector uses Slack Incoming Webhooks. + type: object + required: + - connector_type_id + - name + - secrets + properties: + connector_type_id: + type: string + description: The type of connector. + enum: + - .slack_api + example: .slack_api + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/secrets_properties_slack_api' config_properties_swimlane: title: Connector request properties for a Swimlane connector required: @@ -2129,6 +2163,32 @@ components: name: type: string description: The display name for the connector. + connector_response_properties_slack_api: + title: Connector response properties for a Slack connector + type: object + required: + - connector_type_id + - id + - is_preconfigured + - name + properties: + connector_type_id: + type: string + description: The type of connector. + enum: + - .slack_api + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/is_preconfigured' + name: + type: string + description: The display name for the connector. connector_response_properties_swimlane: title: Connector response properties for a Swimlane connector type: object @@ -2287,6 +2347,7 @@ components: - $ref: '#/components/schemas/connector_response_properties_servicenow_itom' - $ref: '#/components/schemas/connector_response_properties_servicenow_sir' - $ref: '#/components/schemas/connector_response_properties_slack' + - $ref: '#/components/schemas/connector_response_properties_slack_api' - $ref: '#/components/schemas/connector_response_properties_swimlane' - $ref: '#/components/schemas/connector_response_properties_teams' - $ref: '#/components/schemas/connector_response_properties_tines' @@ -2307,6 +2368,7 @@ components: .servicenow-itom: '#/components/schemas/connector_response_properties_servicenow_itom' .servicenow-sir: '#/components/schemas/connector_response_properties_servicenow_sir' .slack: '#/components/schemas/connector_response_properties_slack' + .slack_api: '#/components/schemas/connector_response_properties_slack_api' .swimlane: '#/components/schemas/connector_response_properties_swimlane' .teams: '#/components/schemas/connector_response_properties_teams' .tines: '#/components/schemas/connector_response_properties_tines' @@ -2489,6 +2551,18 @@ components: example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_slack' + update_connector_request_slack_api: + title: Update Slack connector request + type: object + required: + - name + - secrets + properties: + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/secrets_properties_slack_api' update_connector_request_swimlane: title: Update Swimlane connector request type: object @@ -2590,6 +2664,7 @@ components: - .servicenow-sir - .server-log - .slack + - .slack_api - .swimlane - .teams - .tines diff --git a/generated/connectors/connectors.gen.go b/generated/connectors/connectors.gen.go index 750886e3c..4fa1a8a95 100644 --- a/generated/connectors/connectors.gen.go +++ b/generated/connectors/connectors.gen.go @@ -137,6 +137,11 @@ const ( ConnectorResponsePropertiesSlackConnectorTypeIdDotSlack ConnectorResponsePropertiesSlackConnectorTypeId = ".slack" ) +// Defines values for ConnectorResponsePropertiesSlackApiConnectorTypeId. +const ( + ConnectorResponsePropertiesSlackApiConnectorTypeIdDotSlackApi ConnectorResponsePropertiesSlackApiConnectorTypeId = ".slack_api" +) + // Defines values for ConnectorResponsePropertiesSwimlaneConnectorTypeId. const ( ConnectorResponsePropertiesSwimlaneConnectorTypeIdDotSwimlane ConnectorResponsePropertiesSwimlaneConnectorTypeId = ".swimlane" @@ -176,6 +181,7 @@ const ( ConnectorTypesDotServicenowItom ConnectorTypes = ".servicenow-itom" ConnectorTypesDotServicenowSir ConnectorTypes = ".servicenow-sir" ConnectorTypesDotSlack ConnectorTypes = ".slack" + ConnectorTypesDotSlackApi ConnectorTypes = ".slack_api" ConnectorTypesDotSwimlane ConnectorTypes = ".swimlane" ConnectorTypesDotTeams ConnectorTypes = ".teams" ConnectorTypesDotTines ConnectorTypes = ".tines" @@ -243,6 +249,11 @@ const ( CreateConnectorRequestSlackConnectorTypeIdDotSlack CreateConnectorRequestSlackConnectorTypeId = ".slack" ) +// Defines values for CreateConnectorRequestSlackApiConnectorTypeId. +const ( + CreateConnectorRequestSlackApiConnectorTypeIdDotSlackApi CreateConnectorRequestSlackApiConnectorTypeId = ".slack_api" +) + // Defines values for CreateConnectorRequestSwimlaneConnectorTypeId. const ( CreateConnectorRequestSwimlaneConnectorTypeIdDotSwimlane CreateConnectorRequestSwimlaneConnectorTypeId = ".swimlane" @@ -1046,6 +1057,30 @@ type ConnectorResponsePropertiesSlack struct { // ConnectorResponsePropertiesSlackConnectorTypeId The type of connector. type ConnectorResponsePropertiesSlackConnectorTypeId string +// ConnectorResponsePropertiesSlackApi defines model for connector_response_properties_slack_api. +type ConnectorResponsePropertiesSlackApi struct { + // ConnectorTypeId The type of connector. + ConnectorTypeId ConnectorResponsePropertiesSlackApiConnectorTypeId `json:"connector_type_id"` + + // Id The identifier for the connector. + Id string `json:"id"` + + // IsDeprecated Indicates whether the connector type is deprecated. + IsDeprecated *IsDeprecated `json:"is_deprecated,omitempty"` + + // IsMissingSecrets Indicates whether secrets are missing for the connector. Secrets configuration properties vary depending on the connector type. + IsMissingSecrets *IsMissingSecrets `json:"is_missing_secrets,omitempty"` + + // IsPreconfigured Indicates whether it is a preconfigured connector. If true, the `config` and `is_missing_secrets` properties are omitted from the response. + IsPreconfigured IsPreconfigured `json:"is_preconfigured"` + + // Name The display name for the connector. + Name string `json:"name"` +} + +// ConnectorResponsePropertiesSlackApiConnectorTypeId The type of connector. +type ConnectorResponsePropertiesSlackApiConnectorTypeId string + // ConnectorResponsePropertiesSwimlane defines model for connector_response_properties_swimlane. type ConnectorResponsePropertiesSwimlane struct { // Config Defines properties for connectors when type is `.swimlane`. @@ -1383,6 +1418,21 @@ type CreateConnectorRequestSlack struct { // CreateConnectorRequestSlackConnectorTypeId The type of connector. type CreateConnectorRequestSlackConnectorTypeId string +// CreateConnectorRequestSlackApi The Slack connector uses Slack Incoming Webhooks. +type CreateConnectorRequestSlackApi struct { + // ConnectorTypeId The type of connector. + ConnectorTypeId CreateConnectorRequestSlackApiConnectorTypeId `json:"connector_type_id"` + + // Name The display name for the connector. + Name string `json:"name"` + + // Secrets Defines secrets for connectors when type is `.slack`. + Secrets SecretsPropertiesSlackApi `json:"secrets"` +} + +// CreateConnectorRequestSlackApiConnectorTypeId The type of connector. +type CreateConnectorRequestSlackApiConnectorTypeId string + // CreateConnectorRequestSwimlane The Swimlane connector uses the Swimlane REST API to create Swimlane records. type CreateConnectorRequestSwimlane struct { // Config Defines properties for connectors when type is `.swimlane`. @@ -1980,6 +2030,12 @@ type SecretsPropertiesServicenow struct { // SecretsPropertiesSlack Defines secrets for connectors when type is `.slack`. type SecretsPropertiesSlack map[string]interface{} +// SecretsPropertiesSlackApi Defines secrets for connectors when type is `.slack`. +type SecretsPropertiesSlackApi struct { + // Token Slack bot user OAuth token. + Token string `json:"token"` +} + // SecretsPropertiesSwimlane Defines secrets for connectors when type is `.swimlane`. type SecretsPropertiesSwimlane struct { // ApiToken Swimlane API authentication token. @@ -2128,6 +2184,15 @@ type UpdateConnectorRequestSlack struct { Secrets SecretsPropertiesSlack `json:"secrets"` } +// UpdateConnectorRequestSlackApi defines model for update_connector_request_slack_api. +type UpdateConnectorRequestSlackApi struct { + // Name The display name for the connector. + Name string `json:"name"` + + // Secrets Defines secrets for connectors when type is `.slack`. + Secrets SecretsPropertiesSlackApi `json:"secrets"` +} + // UpdateConnectorRequestSwimlane defines model for update_connector_request_swimlane. type UpdateConnectorRequestSwimlane struct { // Config Defines properties for connectors when type is `.swimlane`. @@ -2666,6 +2731,34 @@ func (t *ConnectorResponseProperties) MergeConnectorResponsePropertiesSlack(v Co return err } +// AsConnectorResponsePropertiesSlackApi returns the union data inside the ConnectorResponseProperties as a ConnectorResponsePropertiesSlackApi +func (t ConnectorResponseProperties) AsConnectorResponsePropertiesSlackApi() (ConnectorResponsePropertiesSlackApi, error) { + var body ConnectorResponsePropertiesSlackApi + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromConnectorResponsePropertiesSlackApi overwrites any union data inside the ConnectorResponseProperties as the provided ConnectorResponsePropertiesSlackApi +func (t *ConnectorResponseProperties) FromConnectorResponsePropertiesSlackApi(v ConnectorResponsePropertiesSlackApi) error { + v.ConnectorTypeId = ".slack_api" + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeConnectorResponsePropertiesSlackApi performs a merge with any union data inside the ConnectorResponseProperties, using the provided ConnectorResponsePropertiesSlackApi +func (t *ConnectorResponseProperties) MergeConnectorResponsePropertiesSlackApi(v ConnectorResponsePropertiesSlackApi) error { + v.ConnectorTypeId = ".slack_api" + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JsonMerge(t.union, b) + t.union = merged + return err +} + // AsConnectorResponsePropertiesSwimlane returns the union data inside the ConnectorResponseProperties as a ConnectorResponsePropertiesSwimlane func (t ConnectorResponseProperties) AsConnectorResponsePropertiesSwimlane() (ConnectorResponsePropertiesSwimlane, error) { var body ConnectorResponsePropertiesSwimlane @@ -2844,6 +2937,8 @@ func (t ConnectorResponseProperties) ValueByDiscriminator() (interface{}, error) return t.AsConnectorResponsePropertiesServicenowSir() case ".slack": return t.AsConnectorResponsePropertiesSlack() + case ".slack_api": + return t.AsConnectorResponsePropertiesSlackApi() case ".swimlane": return t.AsConnectorResponsePropertiesSwimlane() case ".teams": diff --git a/internal/clients/kibana/connector.go b/internal/clients/kibana/connector.go index 25e5b8e2f..40777c7e0 100644 --- a/internal/clients/kibana/connector.go +++ b/internal/clients/kibana/connector.go @@ -430,6 +430,9 @@ func createConnectorRequestBody(connector models.KibanaActionConnector) (io.Read case connectors.ConnectorTypesDotSlack: return createConnectorRequestSlack(connector) + case connectors.ConnectorTypesDotSlackApi: + return createConnectorRequestSlackApi(connector) + case connectors.ConnectorTypesDotSwimlane: return createConnectorRequestSwimlane(connector) @@ -488,6 +491,9 @@ func updateConnectorRequestBody(connector models.KibanaActionConnector) (io.Read case connectors.ConnectorTypesDotSlack: return updateConnectorRequestSlack(connector) + case connectors.ConnectorTypesDotSlackApi: + return updateConnectorRequestSlackApi(connector) + case connectors.ConnectorTypesDotSwimlane: return updateConnectorRequestSwimlane(connector) @@ -636,6 +642,15 @@ func createConnectorRequestSlack(connector models.KibanaActionConnector) (io.Rea return marshalConnectorRequest[any](connector, nil, &request.Secrets, &request) } +func createConnectorRequestSlackApi(connector models.KibanaActionConnector) (io.Reader, error) { + request := connectors.CreateConnectorRequestSlackApi{ + ConnectorTypeId: connectors.CreateConnectorRequestSlackApiConnectorTypeIdDotSlackApi, + Name: connector.Name, + } + + return marshalConnectorRequest[any](connector, nil, &request.Secrets, &request) +} + func createConnectorRequestSwimlane(connector models.KibanaActionConnector) (io.Reader, error) { request := connectors.CreateConnectorRequestSwimlane{ ConnectorTypeId: connectors.CreateConnectorRequestSwimlaneConnectorTypeIdDotSwimlane, @@ -777,6 +792,14 @@ func updateConnectorRequestSlack(connector models.KibanaActionConnector) (io.Rea return marshalConnectorRequest[any](connector, nil, &request.Secrets, &request) } +func updateConnectorRequestSlackApi(connector models.KibanaActionConnector) (io.Reader, error) { + request := connectors.UpdateConnectorRequestSlackApi{ + Name: connector.Name, + } + + return marshalConnectorRequest[any](connector, nil, &request.Secrets, &request) +} + func updateConnectorRequestSwimlane(connector models.KibanaActionConnector) (io.Reader, error) { request := connectors.UpdateConnectorRequestSwimlane{ Name: connector.Name, @@ -861,6 +884,9 @@ func connectorResponseToModel(spaceID string, properties connectors.ConnectorRes case connectors.ConnectorTypesDotSlack: return connectorResponseToModelSlack(discriminator, spaceID, properties) + case connectors.ConnectorTypesDotSlackApi: + return connectorResponseToModelSlackApi(discriminator, spaceID, properties) + case connectors.ConnectorTypesDotSwimlane: return connectorResponseToModelSwimlane(discriminator, spaceID, properties) @@ -1306,6 +1332,36 @@ func connectorResponseToModelSlack(discriminator, spaceID string, properties con return &connector, nil } +func connectorResponseToModelSlackApi(discriminator, spaceID string, properties connectors.ConnectorResponseProperties) (*models.KibanaActionConnector, error) { + resp, err := properties.AsConnectorResponsePropertiesSlackApi() + if err != nil { + return nil, err + } + + isDeprecated := false + isMissingSecrets := false + + if resp.IsDeprecated != nil { + isDeprecated = *resp.IsDeprecated + } + + if resp.IsMissingSecrets != nil { + isMissingSecrets = *resp.IsMissingSecrets + } + + connector := models.KibanaActionConnector{ + ConnectorID: resp.Id, + SpaceID: spaceID, + Name: resp.Name, + ConnectorTypeID: discriminator, + IsDeprecated: isDeprecated, + IsMissingSecrets: isMissingSecrets, + IsPreconfigured: bool(resp.IsPreconfigured), + } + + return &connector, nil +} + func connectorResponseToModelSwimlane(discriminator, spaceID string, properties connectors.ConnectorResponseProperties) (*models.KibanaActionConnector, error) { resp, err := properties.AsConnectorResponsePropertiesSwimlane() if err != nil { diff --git a/internal/clients/kibana/connector_test.go b/internal/clients/kibana/connector_test.go index 3be85481b..acaec9f9a 100644 --- a/internal/clients/kibana/connector_test.go +++ b/internal/clients/kibana/connector_test.go @@ -97,6 +97,9 @@ func Test_connectorResponseToModel(t *testing.T) { generator(".slack", nil, func(props *connectors.ConnectorResponseProperties) error { return props.FromConnectorResponsePropertiesSlack(connectors.ConnectorResponsePropertiesSlack{}) }), + generator(".slack_api", nil, func(props *connectors.ConnectorResponseProperties) error { + return props.FromConnectorResponsePropertiesSlackApi(connectors.ConnectorResponsePropertiesSlackApi{}) + }), generator(".swimlane", connectors.ConfigPropertiesSwimlane{}, func(props *connectors.ConnectorResponseProperties) error { return props.FromConnectorResponsePropertiesSwimlane(connectors.ConnectorResponsePropertiesSwimlane{}) }), diff --git a/internal/kibana/connector_test.go b/internal/kibana/connector_test.go index 92a35cbb4..08059f6ac 100644 --- a/internal/kibana/connector_test.go +++ b/internal/kibana/connector_test.go @@ -973,6 +973,72 @@ func TestAccResourceKibanaConnectorSlack(t *testing.T) { }) } +func TestAccResourceKibanaConnectorSlackApi(t *testing.T) { + minSupportedVersion := version.Must(version.NewSemver("8.8.0")) + + connectorName := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum) + + create := func(name string) string { + return fmt.Sprintf(` + provider "elasticstack" { + elasticsearch {} + kibana {} + } + + resource "elasticstack_kibana_action_connector" "test" { + name = "%s" + secrets = jsonencode({ + token = "my-token" + }) + connector_type_id = ".slack_api" + }`, + name) + } + + update := func(name string) string { + return fmt.Sprintf(` + provider "elasticstack" { + elasticsearch {} + kibana {} + } + + resource "elasticstack_kibana_action_connector" "test" { + name = "Updated %s" + secrets = jsonencode({ + token = "my-updated-token" + }) + connector_type_id = ".slack_api" + }`, + name) + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + CheckDestroy: checkResourceKibanaConnectorDestroy, + ProtoV5ProviderFactories: acctest.Providers, + Steps: []resource.TestStep{ + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minSupportedVersion), + Config: create(connectorName), + Check: resource.ComposeTestCheckFunc( + testCommonAttributes(connectorName, ".slack_api"), + + resource.TestMatchResourceAttr("elasticstack_kibana_action_connector.test", "secrets", regexp.MustCompile(`\"token\":\"my-token\"`)), + ), + }, + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minSupportedVersion), + Config: update(connectorName), + Check: resource.ComposeTestCheckFunc( + testCommonAttributes(fmt.Sprintf("Updated %s", connectorName), ".slack_api"), + + resource.TestMatchResourceAttr("elasticstack_kibana_action_connector.test", "secrets", regexp.MustCompile(`\"token\":\"my-updated-token\"`)), + ), + }, + }, + }) +} + func TestAccResourceKibanaConnectorSwimlane(t *testing.T) { minSupportedVersion := version.Must(version.NewSemver("7.14.0"))