From 2d120210a2dce1de0eaac740f63f1f18ccc2556a Mon Sep 17 00:00:00 2001 From: Boris Ilyushonak Date: Wed, 18 Dec 2024 12:48:46 +0100 Subject: [PATCH 01/13] chore: add support 8.16.2 to go-kibana-rest and acc tests --- .github/workflows/test.yml | 4 ++-- Makefile | 2 +- libs/go-kibana-rest/CONTRIBUTING.md | 15 +++++++++++++++ libs/go-kibana-rest/docker-compose.yml | 7 +++---- .../kbapi/api.kibana_spaces_test.go | 2 +- .../kbapi/api.kibana_synthetics_test.go | 19 ------------------- 6 files changed, 22 insertions(+), 27 deletions(-) create mode 100644 libs/go-kibana-rest/CONTRIBUTING.md diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bd3b336d3..6d5793abd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -153,7 +153,7 @@ jobs: - id: setup-fleet name: Setup Fleet - if: matrix.version == '8.10.3' || matrix.version == '8.11.4' || matrix.version == '8.12.2' || matrix.version == '8.13.4' || matrix.version == '8.14.3' || matrix.version == '8.15.3' + if: matrix.version == '8.10.3' || matrix.version == '8.11.4' || matrix.version == '8.12.2' || matrix.version == '8.13.4' || matrix.version == '8.14.3' || matrix.version == '8.15.3' || matrix.version == '8.16.2' run: |- make setup-kibana-fleet env: @@ -162,7 +162,7 @@ jobs: - id: force-install-synthetics name: Force install synthetics - if: matrix.version == '8.14.3' || matrix.version == '8.15.3' + if: matrix.version == '8.14.3' || matrix.version == '8.15.3' || matrix.version == '8.16.2' run: |- for i in {1..5}; do curl -s -H "Authorization: ApiKey ${{ steps.get-api-key.outputs.apikey }}" --header "Content-Type: application/json" --header "kbn-xsrf: true" --request POST --data '{ "force": true }' http://localhost:5601/api/fleet/epm/packages/synthetics/1.2.2 && break || sleep 15; done diff --git a/Makefile b/Makefile index 0dbb5beb7..604bba1ca 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ SWAGGER_VERSION ?= 8.7 GOVERSION ?= $(shell grep -e '^go' go.mod | cut -f 2 -d ' ') -STACK_VERSION ?= 8.15.3 +STACK_VERSION ?= 8.16.2 ELASTICSEARCH_NAME ?= terraform-elasticstack-es ELASTICSEARCH_ENDPOINTS ?= http://$(ELASTICSEARCH_NAME):9200 diff --git a/libs/go-kibana-rest/CONTRIBUTING.md b/libs/go-kibana-rest/CONTRIBUTING.md new file mode 100644 index 000000000..bb08ac7a9 --- /dev/null +++ b/libs/go-kibana-rest/CONTRIBUTING.md @@ -0,0 +1,15 @@ +# Unit tests + +To run the unit tests, you can use the following command: +```bash + +docker compose up -d +make test +``` + +One could enable debug output for tests by setting environment variable `DEBUG=true`, that helps to see http requests and responses. + +Here is an example of environment variables to run a single test, e.g. from IDE or CLI: +```bash +DEBUG=true TEST="-run TestKBAPITestSuite/TestKibanaSpaces ./..." make test +``` \ No newline at end of file diff --git a/libs/go-kibana-rest/docker-compose.yml b/libs/go-kibana-rest/docker-compose.yml index 5cf3a9740..efcd51590 100644 --- a/libs/go-kibana-rest/docker-compose.yml +++ b/libs/go-kibana-rest/docker-compose.yml @@ -1,6 +1,6 @@ services: elasticsearch: - image: docker.elastic.co/elasticsearch/elasticsearch:8.16.1@sha256:500b04e9282aeffd083fb8f917ee2c309c99f76c095c79681bd77ab37d6886e6 + image: docker.elastic.co/elasticsearch/elasticsearch:8.16.2 environment: cluster.name: test discovery.type: single-node @@ -11,7 +11,7 @@ services: ports: - "9200:9200/tcp" set-kibana-password: - image: docker.elastic.co/kibana/kibana:8.16.1@sha256:a22f9f9bb16fc7b01cfd03523a2d5a0d9873daefec6092368a8e2bb0b3380757 + image: docker.elastic.co/kibana/kibana:8.16.2 restart: on-failure links: - elasticsearch @@ -22,14 +22,13 @@ services: elasticsearch: condition: service_started kibana: - image: docker.elastic.co/kibana/kibana:8.16.1@sha256:a22f9f9bb16fc7b01cfd03523a2d5a0d9873daefec6092368a8e2bb0b3380757 + image: docker.elastic.co/kibana/kibana:8.16.2 environment: SERVER_NAME: kibana ELASTICSEARCH_HOSTS: http://es:9200 ELASTICSEARCH_USERNAME: kibana_system ELASTICSEARCH_PASSWORD: changeme XPACK_ENCRYPTEDSAVEDOBJECTS_ENCRYPTIONKEY: min-32-byte-long-strong-encryption-key -# LOGGING_ROOT_LEVEL: debug links: - elasticsearch:es ports: diff --git a/libs/go-kibana-rest/kbapi/api.kibana_spaces_test.go b/libs/go-kibana-rest/kbapi/api.kibana_spaces_test.go index 02596a9f0..6fcde0b59 100644 --- a/libs/go-kibana-rest/kbapi/api.kibana_spaces_test.go +++ b/libs/go-kibana-rest/kbapi/api.kibana_spaces_test.go @@ -42,7 +42,7 @@ func (s *KBAPITestSuite) TestKibanaSpaces() { Objects: []KibanaSpaceObjectParameter{ { Type: "config", - ID: "8.15.0", + ID: "8.16.2", }, }, } diff --git a/libs/go-kibana-rest/kbapi/api.kibana_synthetics_test.go b/libs/go-kibana-rest/kbapi/api.kibana_synthetics_test.go index fd527cf17..4d665df1b 100644 --- a/libs/go-kibana-rest/kbapi/api.kibana_synthetics_test.go +++ b/libs/go-kibana-rest/kbapi/api.kibana_synthetics_test.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "testing" - "time" "github.com/go-resty/resty/v2" "github.com/google/uuid" @@ -369,7 +368,6 @@ func (s *KBAPITestSuite) TestKibanaSyntheticsMonitorAPI() { monitor, err := syntheticsAPI.Monitor.Add(ctx, config, fields, space) assert.NoError(s.T(), err) assert.NotNil(s.T(), monitor) - updateDueToKibanaAPIDiff(monitor) get, err := syntheticsAPI.Monitor.Get(ctx, monitor.Id, space) assert.NoError(s.T(), err) @@ -382,11 +380,9 @@ func (s *KBAPITestSuite) TestKibanaSyntheticsMonitorAPI() { update, err := syntheticsAPI.Monitor.Update(ctx, monitor.Id, tc.update.config, tc.update.fields, space) assert.NoError(s.T(), err) assert.NotNil(s.T(), update) - updateDueToKibanaAPIDiff(update) get, err = syntheticsAPI.Monitor.Get(ctx, monitor.ConfigId, space) assert.NoError(s.T(), err) - get.CreatedAt = time.Time{} // update response doesn't have created_at field assert.Equal(s.T(), update, get) deleted, err := syntheticsAPI.Monitor.Delete(ctx, space, monitor.ConfigId) @@ -410,21 +406,6 @@ func (s *KBAPITestSuite) TestKibanaSyntheticsMonitorAPI() { } } -// see https://github.com/elastic/kibana/issues/189906 -func updateDueToKibanaAPIDiff(m *SyntheticsMonitor) { - m.Params = nil - m.Username = "" - m.Password = "" - m.ProxyHeaders = nil - m.CheckResponseBodyPositive = nil - m.CheckRequestBody = nil - m.CheckRequestHeaders = nil - m.CheckSend = "" - m.CheckReceive = "" - m.InlineScript = "" - m.SyntheticsArgs = nil -} - func (s *KBAPITestSuite) TestKibanaSyntheticsPrivateLocationAPI() { ctx := context.Background() From ae4b47bfce95f6e34e43489011c50884fe10e429 Mon Sep 17 00:00:00 2001 From: Boris Ilyushonak Date: Wed, 18 Dec 2024 13:30:50 +0100 Subject: [PATCH 02/13] try to fix GetDataStreamLifecycle --- CONTRIBUTING.md | 10 ++++++++++ internal/clients/elasticsearch/index.go | 7 +++++-- 2 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..2108d8cc3 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,10 @@ +## Acceptance tests + +```bash +make docker-testacc +``` + +Run a single test with terraform debug enabled: +```bash +make docker-testacc TF_LOG=DEBUG TESTARGS='-run ^TestAccResourceDataStreamLifecycle$$' +``` \ No newline at end of file diff --git a/internal/clients/elasticsearch/index.go b/internal/clients/elasticsearch/index.go index 6af28ba8e..c2de64d5c 100644 --- a/internal/clients/elasticsearch/index.go +++ b/internal/clients/elasticsearch/index.go @@ -548,11 +548,14 @@ func GetDataStreamLifecycle(ctx context.Context, apiClient *clients.ApiClient, d return nil, utils.FrameworkDiagsFromSDK(diags) } - dStreams := make(map[string][]models.DataStreamLifecycle) + dStreams := struct { + DataStreams []models.DataStreamLifecycle `json:"data_streams,omitempty"` + }{} + if err := json.NewDecoder(res.Body).Decode(&dStreams); err != nil { return nil, utils.FrameworkDiagFromError(err) } - ds := dStreams["data_streams"] + ds := dStreams.DataStreams return &ds, nil } From 128b011119af014807346b9f10d4c7e726bb0af9 Mon Sep 17 00:00:00 2001 From: Boris Ilyushonak Date: Wed, 18 Dec 2024 16:54:33 +0100 Subject: [PATCH 03/13] restrict kibana versions for TestAccResourceIntegrationPolicySecretsFromSDK --- internal/fleet/integration_policy/resource_test.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/internal/fleet/integration_policy/resource_test.go b/internal/fleet/integration_policy/resource_test.go index de15e0174..f2c4aeaa2 100644 --- a/internal/fleet/integration_policy/resource_test.go +++ b/internal/fleet/integration_policy/resource_test.go @@ -75,6 +75,9 @@ func TestAccResourceIntegrationPolicy(t *testing.T) { func TestAccResourceIntegrationPolicySecretsFromSDK(t *testing.T) { policyName := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum) + sdkConstrains, err := version.NewConstraint(">=8.10.0,<8.16.0") + require.NoError(t, err) + resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, CheckDestroy: checkResourceIntegrationPolicyDestroy, @@ -86,7 +89,7 @@ func TestAccResourceIntegrationPolicySecretsFromSDK(t *testing.T) { VersionConstraint: "0.11.7", }, }, - SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionIntegrationPolicy), + SkipFunc: versionutils.CheckIfVersionMeetsConstraints(sdkConstrains), Config: testAccResourceIntegrationPolicySecretsCreate(policyName, "created"), ExpectNonEmptyPlan: true, // secret churn Check: resource.ComposeTestCheckFunc( @@ -103,7 +106,7 @@ func TestAccResourceIntegrationPolicySecretsFromSDK(t *testing.T) { }, { ProtoV6ProviderFactories: acctest.Providers, - SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionIntegrationPolicy), + SkipFunc: versionutils.CheckIfVersionMeetsConstraints(sdkConstrains), Config: testAccResourceIntegrationPolicySecretsCreate(policyName, "created"), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "name", policyName), From 8a95e094d9be01224d2a303c91a32d34fae066ac Mon Sep 17 00:00:00 2001 From: Boris Ilyushonak Date: Wed, 18 Dec 2024 17:23:03 +0100 Subject: [PATCH 04/13] fix `TestAccDataSourceKibanaSecurityRole` test --- internal/kibana/role.go | 7 ++----- libs/go-kibana-rest/kbapi/api.kibana_role_management.go | 7 ++++++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/internal/kibana/role.go b/internal/kibana/role.go index 98f028098..c19aed808 100644 --- a/internal/kibana/role.go +++ b/internal/kibana/role.go @@ -265,14 +265,11 @@ func resourceRoleUpsert(ctx context.Context, d *schema.ResourceData, meta interf if err != nil { return diag.FromErr(err) } - queryParams := "" - if d.IsNewResource() { - queryParams = "?createOnly=true" - } kibanaRole := kbapi.KibanaRole{ - Name: fmt.Sprintf("%s%s", d.Get("name").(string), queryParams), + Name: d.Get("name").(string), Kibana: []kbapi.KibanaRoleKibana{}, Elasticsearch: &kbapi.KibanaRoleElasticsearch{}, + CreateOnly: d.IsNewResource(), } if v, ok := d.GetOk("kibana"); ok { diff --git a/libs/go-kibana-rest/kbapi/api.kibana_role_management.go b/libs/go-kibana-rest/kbapi/api.kibana_role_management.go index 2ab419515..2451cb637 100644 --- a/libs/go-kibana-rest/kbapi/api.kibana_role_management.go +++ b/libs/go-kibana-rest/kbapi/api.kibana_role_management.go @@ -19,6 +19,7 @@ type KibanaRole struct { TransientMedata *KibanaRoleTransientMetadata `json:"transient_metadata,omitempty"` Elasticsearch *KibanaRoleElasticsearch `json:"elasticsearch,omitempty"` Kibana []KibanaRoleKibana `json:"kibana,omitempty"` + CreateOnly bool `json:"-"` } // KibanaRoleTransientMetadata is the API TransientMedata object @@ -153,7 +154,11 @@ func newKibanaRoleManagementCreateOrUpdateFunc(c *resty.Client) KibanaRoleManage if err != nil { return nil, err } - resp, err := c.R().SetBody(jsonData).Put(path) + r := c.R() + if kibanaRole.CreateOnly { + r = r.SetQueryParam("createOnly", "true") + } + resp, err := r.SetBody(jsonData).Put(path) if err != nil { return nil, err } From 23293b6a57850ce6500fb9f7bdb7adb7e168a18f Mon Sep 17 00:00:00 2001 From: Boris Ilyushonak Date: Thu, 19 Dec 2024 18:19:16 +0100 Subject: [PATCH 05/13] feat: update synthetics implementation according to Kibana 8.16 API changes --- CONTRIBUTING.md | 7 +++- internal/kibana/synthetics/acc_test.go | 33 ++++++++++++++++++- internal/kibana/synthetics/schema.go | 22 ++++++++++++- .../kbapi/api.kibana_synthetics.go | 11 +++++-- .../kbapi/api.kibana_synthetics_test.go | 23 +++++++++---- 5 files changed, 83 insertions(+), 13 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2108d8cc3..7a14427e4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,5 +6,10 @@ make docker-testacc Run a single test with terraform debug enabled: ```bash -make docker-testacc TF_LOG=DEBUG TESTARGS='-run ^TestAccResourceDataStreamLifecycle$$' +env TF_LOG=DEBUG make docker-testacc TESTARGS='-run ^TestAccResourceDataStreamLifecycle$$' +``` + +A way to forward debug logs to a file: +```bash +env TF_ACC_LOG_PATH=/tmp/tf.log TF_ACC_LOG=DEBUG TF_LOG=DEBUG make docker-testacc ``` \ No newline at end of file diff --git a/internal/kibana/synthetics/acc_test.go b/internal/kibana/synthetics/acc_test.go index 664a5a847..a4c68330b 100644 --- a/internal/kibana/synthetics/acc_test.go +++ b/internal/kibana/synthetics/acc_test.go @@ -2,12 +2,12 @@ package synthetics_test import ( "fmt" - sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "testing" "github.com/elastic/terraform-provider-elasticstack/internal/acctest" "github.com/elastic/terraform-provider-elasticstack/internal/versionutils" "github.com/hashicorp/go-version" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,7 +15,25 @@ var ( minKibanaVersion = version.Must(version.NewVersion("8.14.0")) ) +/* +TODOs: +- [ ] TF schema - fix https://github.com/elastic/terraform-provider-elasticstack/issues/965 +- [ ] TF schema - fix https://github.com/elastic/terraform-provider-elasticstack/issues/916 +- [ ] TF schema - test imports after 8.16 fixes +- [ ] Update change log +*/ + const ( + httpMonitorMinConfig = ` + +resource "elasticstack_kibana_synthetics_monitor" "%s" { + name = "TestHttpMonitorResource - %s" + private_locations = [elasticstack_kibana_synthetics_private_location.%s.label] + http = { + url = "http://localhost:5601" + } +} +` httpMonitorConfig = ` resource "elasticstack_kibana_synthetics_monitor" "%s" { @@ -268,12 +286,25 @@ func TestSyntheticMonitorHTTPResource(t *testing.T) { name := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum) id := "http-monitor" httpMonitorId, config := testMonitorConfig(id, httpMonitorConfig, name) + bmName := fmt.Sprintf("%s-", name) + bmHttpMonitorId, bmConfig := testMonitorConfig(fmt.Sprintf("%s-min", id), httpMonitorMinConfig, bmName) _, configUpdated := testMonitorConfig(id, httpMonitorUpdated, name) resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.Providers, Steps: []resource.TestStep{ + // Create and Read http monitor with minimum fields + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minKibanaVersion), + Config: bmConfig, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet(bmHttpMonitorId, "id"), + resource.TestCheckResourceAttr(httpMonitorId, "name", "TestHttpMonitorResource - "+bmName), + resource.TestCheckResourceAttr(httpMonitorId, "space_id", "default"), + resource.TestCheckResourceAttr(httpMonitorId, "http.url", "http://localhost:5601"), + ), + }, // Create and Read http monitor { SkipFunc: versionutils.CheckIfVersionIsUnsupported(minKibanaVersion), diff --git a/internal/kibana/synthetics/schema.go b/internal/kibana/synthetics/schema.go index 8fc9c0fae..b17e15212 100644 --- a/internal/kibana/synthetics/schema.go +++ b/internal/kibana/synthetics/schema.go @@ -132,8 +132,10 @@ func monitorConfigSchema() schema.Schema { MarkdownDescription: "The namespace field should be lowercase and not contain spaces. The namespace must not include any of the following characters: *, \\, /, ?, \", <, >, |, whitespace, ,, #, :, or -. Default: `default`", Optional: true, PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), stringplanmodifier.RequiresReplace(), }, + Computed: true, }, "schedule": schema.Int64Attribute{ Optional: true, @@ -141,6 +143,8 @@ func monitorConfigSchema() schema.Schema { Validators: []validator.Int64{ int64validator.OneOf(1, 3, 5, 10, 15, 30, 60, 120, 240), }, + Computed: true, + PlanModifiers: []planmodifier.Int64{int64planmodifier.UseStateForUnknown()}, }, "locations": schema.ListAttribute{ ElementType: types.StringType, @@ -171,6 +175,8 @@ func monitorConfigSchema() schema.Schema { "enabled": schema.BoolAttribute{ Optional: true, MarkdownDescription: "Whether the monitor is enabled. Default: `true`", + Computed: true, + PlanModifiers: []planmodifier.Bool{boolplanmodifier.UseStateForUnknown()}, }, "tags": schema.ListAttribute{ ElementType: types.StringType, @@ -181,10 +187,14 @@ func monitorConfigSchema() schema.Schema { "service_name": schema.StringAttribute{ Optional: true, MarkdownDescription: "The APM service name.", + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, }, "timeout": schema.Int64Attribute{ Optional: true, MarkdownDescription: "The monitor timeout in seconds, monitor will fail if it doesn’t complete within this time. Default: `16`", + Computed: true, + PlanModifiers: []planmodifier.Int64{int64planmodifier.UseStateForUnknown()}, }, "params": jsonObjectSchema("Monitor parameters"), "http": httpMonitorFieldsSchema(), @@ -267,7 +277,9 @@ func statusConfigSchema() schema.Attribute { Optional: true, Attributes: map[string]schema.Attribute{ "enabled": schema.BoolAttribute{ - Optional: true, + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.Bool{boolplanmodifier.UseStateForUnknown()}, }, }, } @@ -281,6 +293,8 @@ func monitorAlertConfigSchema() schema.Attribute { "status": statusConfigSchema(), "tls": statusConfigSchema(), }, + Computed: true, + //PlanModifiers: []planmodifier.Object{objectplanmodifier.UseStateForUnknown()}, //TODO: verify if that is correct } } @@ -319,14 +333,20 @@ func httpMonitorFieldsSchema() schema.Attribute { Validators: []validator.String{ stringvalidator.OneOf("any", "all"), }, + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, }, "ipv4": schema.BoolAttribute{ Optional: true, MarkdownDescription: "Whether to ping using the ipv4 protocol.", + Computed: true, + PlanModifiers: []planmodifier.Bool{boolplanmodifier.UseStateForUnknown()}, }, "ipv6": schema.BoolAttribute{ Optional: true, MarkdownDescription: "Whether to ping using the ipv6 protocol.", + Computed: true, + PlanModifiers: []planmodifier.Bool{boolplanmodifier.UseStateForUnknown()}, }, "username": schema.StringAttribute{ Optional: true, diff --git a/libs/go-kibana-rest/kbapi/api.kibana_synthetics.go b/libs/go-kibana-rest/kbapi/api.kibana_synthetics.go index d4cb97855..590e3dcf4 100644 --- a/libs/go-kibana-rest/kbapi/api.kibana_synthetics.go +++ b/libs/go-kibana-rest/kbapi/api.kibana_synthetics.go @@ -109,7 +109,8 @@ type BrowserMonitorFields struct { } type TCPMonitorFields struct { - Host string `json:"host"` + Host string `json:"host"` + //TODO: support certificate_authorities, certificate, key, key_passphrase SslVerificationMode string `json:"ssl.verification_mode,omitempty"` SslSupportedProtocols []string `json:"ssl.supported_protocols,omitempty"` CheckSend string `json:"check.send,omitempty"` @@ -119,7 +120,8 @@ type TCPMonitorFields struct { } type HTTPMonitorFields struct { - Url string `json:"url"` + Url string `json:"url"` + //TODO: support certificate_authorities, certificate, key, key_passphrase SslVerificationMode string `json:"ssl.verification_mode,omitempty"` SslSupportedProtocols []string `json:"ssl.supported_protocols,omitempty"` MaxRedirects string `json:"max_redirects,omitempty"` @@ -222,9 +224,12 @@ type SyntheticsMonitor struct { CheckRequestHeaders JsonObject `json:"check.request.headers,omitempty"` CheckRequestMethod string `json:"check.request.method,omitempty"` //http and tcp - ProxyUrl string `json:"proxy_url,omitempty"` + ProxyUrl string `json:"proxy_url,omitempty"` + //TODO: support certificate_authorities, certificate, key, key_passphrase + SslVerificationMode string `json:"ssl.verification_mode"` SslSupportedProtocols []string `json:"ssl.supported_protocols"` + //tcp and icmp Host string `json:"host,omitempty"` //tcp diff --git a/libs/go-kibana-rest/kbapi/api.kibana_synthetics_test.go b/libs/go-kibana-rest/kbapi/api.kibana_synthetics_test.go index 4d665df1b..8bf8386ad 100644 --- a/libs/go-kibana-rest/kbapi/api.kibana_synthetics_test.go +++ b/libs/go-kibana-rest/kbapi/api.kibana_synthetics_test.go @@ -149,12 +149,21 @@ func (s *KBAPITestSuite) TestKibanaSyntheticsMonitorAPI() { Url: "http://localhost:5601", SslSupportedProtocols: []string{"TLSv1.0", "TLSv1.1", "TLSv1.2"}, SslVerificationMode: "full", - MaxRedirects: "2", - Mode: ModeAny, - Ipv4: t, - Ipv6: f, - Username: "test-user-name", - Password: "test-password", + //Ssl: map[string]interface{}{ + // "verification_mode": "full", + // "supported_protocols": []string{"TLSv1.0", "TLSv1.1", "TLSv1.2"}, + // + // "certificate_authorities": []string{"ca1", "ca2"}, + // "certificate": "cert", + // "key": "key", + // "key_passphrase": "passphrase", + //}, + MaxRedirects: "2", + Mode: ModeAny, + Ipv4: t, + Ipv6: f, + Username: "test-user-name", + Password: "test-password", ProxyHeader: map[string]interface{}{ "User-Agent": "test", }, @@ -298,7 +307,7 @@ func (s *KBAPITestSuite) TestKibanaSyntheticsMonitorAPI() { Name: fmt.Sprintf("test synthetics browser monitor %s", testUuid), PrivateLocations: []string{location.Label}, }, - fields: BrowserMonitorFields{ + fields: BrowserMonitorFields{ //TODO: check that get returns it - inline_script InlineScript: `step('Go to https://google.com.co', () => page.goto('https://www.google.com'))`, }, }, From acd01c29390cb6db6a4b5358922d95d923998fc5 Mon Sep 17 00:00:00 2001 From: Boris Ilyushonak Date: Fri, 20 Dec 2024 11:42:53 +0100 Subject: [PATCH 06/13] add bare min http monitor test, skip alert config for now --- internal/kibana/synthetics/acc_test.go | 20 +++++++++++++++----- internal/kibana/synthetics/schema.go | 5 ++++- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/internal/kibana/synthetics/acc_test.go b/internal/kibana/synthetics/acc_test.go index a4c68330b..638b3975f 100644 --- a/internal/kibana/synthetics/acc_test.go +++ b/internal/kibana/synthetics/acc_test.go @@ -29,6 +29,14 @@ const ( resource "elasticstack_kibana_synthetics_monitor" "%s" { name = "TestHttpMonitorResource - %s" private_locations = [elasticstack_kibana_synthetics_private_location.%s.label] + alert = { + status = { + enabled = false + } + tls = { + enabled = false + } + } http = { url = "http://localhost:5601" } @@ -286,8 +294,10 @@ func TestSyntheticMonitorHTTPResource(t *testing.T) { name := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum) id := "http-monitor" httpMonitorId, config := testMonitorConfig(id, httpMonitorConfig, name) - bmName := fmt.Sprintf("%s-", name) - bmHttpMonitorId, bmConfig := testMonitorConfig(fmt.Sprintf("%s-min", id), httpMonitorMinConfig, bmName) + + bmName := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum) + bmHttpMonitorId, bmConfig := testMonitorConfig("http-monitor-min", httpMonitorMinConfig, bmName) + _, configUpdated := testMonitorConfig(id, httpMonitorUpdated, name) resource.Test(t, resource.TestCase{ @@ -300,9 +310,9 @@ func TestSyntheticMonitorHTTPResource(t *testing.T) { Config: bmConfig, Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrSet(bmHttpMonitorId, "id"), - resource.TestCheckResourceAttr(httpMonitorId, "name", "TestHttpMonitorResource - "+bmName), - resource.TestCheckResourceAttr(httpMonitorId, "space_id", "default"), - resource.TestCheckResourceAttr(httpMonitorId, "http.url", "http://localhost:5601"), + resource.TestCheckResourceAttr(bmHttpMonitorId, "name", "TestHttpMonitorResource - "+bmName), + resource.TestCheckResourceAttr(bmHttpMonitorId, "space_id", "default"), + resource.TestCheckResourceAttr(bmHttpMonitorId, "http.url", "http://localhost:5601"), ), }, // Create and Read http monitor diff --git a/internal/kibana/synthetics/schema.go b/internal/kibana/synthetics/schema.go index b17e15212..8eb8c3923 100644 --- a/internal/kibana/synthetics/schema.go +++ b/internal/kibana/synthetics/schema.go @@ -293,7 +293,10 @@ func monitorAlertConfigSchema() schema.Attribute { "status": statusConfigSchema(), "tls": statusConfigSchema(), }, - Computed: true, + //Computed: true, + // try object type and + //types.ObjectValueFrom() + //tfsdk.ValueAs() //PlanModifiers: []planmodifier.Object{objectplanmodifier.UseStateForUnknown()}, //TODO: verify if that is correct } } From 881605bad35b64008c95fd70eddbfed2cfa08929 Mon Sep 17 00:00:00 2001 From: Boris Ilyushonak Date: Fri, 20 Dec 2024 11:50:15 +0100 Subject: [PATCH 07/13] add import test for browser monitor and generate docs --- CONTRIBUTING.md | 10 ++++++++++ docs/resources/kibana_synthetics_monitor.md | 7 +------ internal/kibana/synthetics/acc_test.go | 19 ++++++++++--------- .../kibana_synthetics_monitor.md.tmpl | 7 +------ 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7a14427e4..a59645a66 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,4 +12,14 @@ env TF_LOG=DEBUG make docker-testacc TESTARGS='-run ^TestAccResourceDataStreamLi A way to forward debug logs to a file: ```bash env TF_ACC_LOG_PATH=/tmp/tf.log TF_ACC_LOG=DEBUG TF_LOG=DEBUG make docker-testacc +``` + + +## Typical development workflow + +```bash + +make docs-generate + +make testacc ``` \ No newline at end of file diff --git a/docs/resources/kibana_synthetics_monitor.md b/docs/resources/kibana_synthetics_monitor.md index 1447afd71..0516e68f9 100644 --- a/docs/resources/kibana_synthetics_monitor.md +++ b/docs/resources/kibana_synthetics_monitor.md @@ -183,9 +183,4 @@ Import is supported using the following syntax: ```shell terraform import elasticstack_kibana_synthetics_monitor.my_monitor / -``` - -**NOTE:** Not all monitor fields are supported during the import due-to API limitation. -Full field support could be implemented after this [kibana issue](https://github.com/elastic/kibana/issues/189906) is resolved. - -Currently not supported fields during the import: `params`, `retest_on_failure`, `locations`, `http.proxy_header`, `http.username`, `http.password`, `http.check`, `http.response`, `tcp.check_send`, `tcp.check_receive` and monitor type `browser` +``` \ No newline at end of file diff --git a/internal/kibana/synthetics/acc_test.go b/internal/kibana/synthetics/acc_test.go index 638b3975f..d6416af28 100644 --- a/internal/kibana/synthetics/acc_test.go +++ b/internal/kibana/synthetics/acc_test.go @@ -13,6 +13,7 @@ import ( var ( minKibanaVersion = version.Must(version.NewVersion("8.14.0")) + kibana816Version = version.Must(version.NewVersion("8.16.0")) ) /* @@ -603,15 +604,15 @@ func TestSyntheticMonitorBrowserResource(t *testing.T) { resource.TestCheckResourceAttr(browserMonitorId, "browser.inline_script", "step('Go to https://google.com.co', () => page.goto('https://www.google.com'))"), ), }, - // ImportState testing - kibana doesn't return required parameter inline_script for browser monitor, so import state is not supported till the fix - /* { - SkipFunc: versionutils.CheckIfVersionIsUnsupported(minKibanaVersion), - ResourceName: browserMonitorId, - ImportState: true, - ImportStateVerify: true, - Config: config, - }, - */ // Update and Read browser monitor + // ImportState testing + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(kibana816Version), + ResourceName: browserMonitorId, + ImportState: true, + ImportStateVerify: true, + Config: config, + }, + // Update and Read browser monitor { SkipFunc: versionutils.CheckIfVersionIsUnsupported(minKibanaVersion), ResourceName: browserMonitorId, diff --git a/templates/resources/kibana_synthetics_monitor.md.tmpl b/templates/resources/kibana_synthetics_monitor.md.tmpl index 32c971d0c..6f99d891e 100644 --- a/templates/resources/kibana_synthetics_monitor.md.tmpl +++ b/templates/resources/kibana_synthetics_monitor.md.tmpl @@ -31,9 +31,4 @@ In case you would like to reset an optional monitor value, please set it explici Import is supported using the following syntax: -{{ codefile "shell" "examples/resources/elasticstack_kibana_synthetics_monitor/import.sh" }} - -**NOTE:** Not all monitor fields are supported during the import due-to API limitation. -Full field support could be implemented after this [kibana issue](https://github.com/elastic/kibana/issues/189906) is resolved. - -Currently not supported fields during the import: `params`, `retest_on_failure`, `locations`, `http.proxy_header`, `http.username`, `http.password`, `http.check`, `http.response`, `tcp.check_send`, `tcp.check_receive` and monitor type `browser` +{{ codefile "shell" "examples/resources/elasticstack_kibana_synthetics_monitor/import.sh" }} \ No newline at end of file From 20ce345d0b7a14e07c8283abcbf186711ff8cce0 Mon Sep 17 00:00:00 2001 From: Boris Ilyushonak Date: Fri, 20 Dec 2024 13:27:01 +0100 Subject: [PATCH 08/13] extend schema with ssl attributes support --- CONTRIBUTING.md | 28 ++- docs/resources/kibana_synthetics_monitor.md | 8 + internal/kibana/synthetics/acc_test.go | 2 +- internal/kibana/synthetics/schema.go | 191 ++++++++++++------ internal/kibana/synthetics/schema_test.go | 42 ++-- .../kbapi/api.kibana_synthetics.go | 62 +++--- .../kbapi/api.kibana_synthetics_test.go | 33 +-- 7 files changed, 242 insertions(+), 124 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a59645a66..6ee58a789 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,7 @@ +# Typical development workflow + +Fork the repo, work on an issue + ## Acceptance tests ```bash @@ -15,11 +19,27 @@ env TF_ACC_LOG_PATH=/tmp/tf.log TF_ACC_LOG=DEBUG TF_LOG=DEBUG make docker-testac ``` -## Typical development workflow +## Update documentation +Update documentation templates in `./templates` directory and re-generate docs via: ```bash - make docs-generate +``` + +## Update `./CHANGELOG.md` + +List of previous commits is a good example of what should be included in the changelog. + + +## Pull request + +Format the code before pushing: +```bash +make fmt +``` + +Create a PR and check acceptance test matrix is green. + +## Run provider with local terraform -make testacc -``` \ No newline at end of file +TBD \ No newline at end of file diff --git a/docs/resources/kibana_synthetics_monitor.md b/docs/resources/kibana_synthetics_monitor.md index 0516e68f9..31e36a770 100644 --- a/docs/resources/kibana_synthetics_monitor.md +++ b/docs/resources/kibana_synthetics_monitor.md @@ -144,6 +144,10 @@ Optional: - `proxy_header` (String) Additional headers to send to proxies during CONNECT requests.. Raw JSON object, use `jsonencode` function to represent JSON - `proxy_url` (String) The URL of the proxy to use for this monitor. - `response` (String) Controls the indexing of the HTTP response body contents to the `http.response.body.contents` field.. Raw JSON object, use `jsonencode` function to represent JSON +- `ssl_certificate` (String) Certificate. +- `ssl_certificate_authorities` (List of String) The list of root certificates for verifications is required. +- `ssl_key` (String) Certificate key. +- `ssl_key_passphrase` (String) Key passphrase. - `ssl_supported_protocols` (List of String) List of allowed SSL/TLS versions. - `ssl_verification_mode` (String) Controls the verification of server certificates. - `username` (String) The username for authenticating with the server. The credentials are passed with the request. @@ -174,6 +178,10 @@ Optional: - `check_send` (String) An optional payload string to send to the remote host. - `proxy_url` (String) The URL of the SOCKS5 proxy to use when connecting to the server. The value must be a URL with a scheme of `socks5://`. If the SOCKS5 proxy server requires client authentication, then a username and password can be embedded in the URL. When using a proxy, hostnames are resolved on the proxy server instead of on the client. You can change this behavior by setting the `proxy_use_local_resolver` option. - `proxy_use_local_resolver` (Boolean) A Boolean value that determines whether hostnames are resolved locally instead of being resolved on the proxy server. The default value is false, which means that name resolution occurs on the proxy server. +- `ssl_certificate` (String) Certificate. +- `ssl_certificate_authorities` (List of String) The list of root certificates for verifications is required. +- `ssl_key` (String) Certificate key. +- `ssl_key_passphrase` (String) Key passphrase. - `ssl_supported_protocols` (List of String) List of allowed SSL/TLS versions. - `ssl_verification_mode` (String) Controls the verification of server certificates. diff --git a/internal/kibana/synthetics/acc_test.go b/internal/kibana/synthetics/acc_test.go index d6416af28..7683f0de6 100644 --- a/internal/kibana/synthetics/acc_test.go +++ b/internal/kibana/synthetics/acc_test.go @@ -20,7 +20,7 @@ var ( TODOs: - [ ] TF schema - fix https://github.com/elastic/terraform-provider-elasticstack/issues/965 - [ ] TF schema - fix https://github.com/elastic/terraform-provider-elasticstack/issues/916 -- [ ] TF schema - test imports after 8.16 fixes +- [x] TF schema - test imports after 8.16 fixes - [ ] Update change log */ diff --git a/internal/kibana/synthetics/schema.go b/internal/kibana/synthetics/schema.go index 8eb8c3923..8ae1ae174 100644 --- a/internal/kibana/synthetics/schema.go +++ b/internal/kibana/synthetics/schema.go @@ -43,29 +43,39 @@ type tfAlertConfigV0 struct { } type tfHTTPMonitorFieldsV0 struct { - URL types.String `tfsdk:"url"` - SslVerificationMode types.String `tfsdk:"ssl_verification_mode"` - SslSupportedProtocols types.List `tfsdk:"ssl_supported_protocols"` - MaxRedirects types.Int64 `tfsdk:"max_redirects"` - Mode types.String `tfsdk:"mode"` - IPv4 types.Bool `tfsdk:"ipv4"` - IPv6 types.Bool `tfsdk:"ipv6"` - ProxyURL types.String `tfsdk:"proxy_url"` - ProxyHeader jsontypes.Normalized `tfsdk:"proxy_header"` - Username types.String `tfsdk:"username"` - Password types.String `tfsdk:"password"` - Response jsontypes.Normalized `tfsdk:"response"` - Check jsontypes.Normalized `tfsdk:"check"` + URL types.String `tfsdk:"url"` + MaxRedirects types.Int64 `tfsdk:"max_redirects"` + Mode types.String `tfsdk:"mode"` + IPv4 types.Bool `tfsdk:"ipv4"` + IPv6 types.Bool `tfsdk:"ipv6"` + ProxyURL types.String `tfsdk:"proxy_url"` + ProxyHeader jsontypes.Normalized `tfsdk:"proxy_header"` + Username types.String `tfsdk:"username"` + Password types.String `tfsdk:"password"` + Response jsontypes.Normalized `tfsdk:"response"` + Check jsontypes.Normalized `tfsdk:"check"` + + SslVerificationMode types.String `tfsdk:"ssl_verification_mode"` + SslSupportedProtocols types.List `tfsdk:"ssl_supported_protocols"` + SslCertificateAuthorities []types.String `tfsdk:"ssl_certificate_authorities"` + SslCertificate types.String `tfsdk:"ssl_certificate"` + SslKey types.String `tfsdk:"ssl_key"` + SslKeyPassphrase types.String `tfsdk:"ssl_key_passphrase"` } type tfTCPMonitorFieldsV0 struct { Host types.String `tfsdk:"host"` - SslVerificationMode types.String `tfsdk:"ssl_verification_mode"` - SslSupportedProtocols types.List `tfsdk:"ssl_supported_protocols"` CheckSend types.String `tfsdk:"check_send"` CheckReceive types.String `tfsdk:"check_receive"` ProxyURL types.String `tfsdk:"proxy_url"` ProxyUseLocalResolver types.Bool `tfsdk:"proxy_use_local_resolver"` + + SslVerificationMode types.String `tfsdk:"ssl_verification_mode"` + SslSupportedProtocols types.List `tfsdk:"ssl_supported_protocols"` + SslCertificateAuthorities []types.String `tfsdk:"ssl_certificate_authorities"` + SslCertificate types.String `tfsdk:"ssl_certificate"` + SslKey types.String `tfsdk:"ssl_key"` + SslKeyPassphrase types.String `tfsdk:"ssl_key_passphrase"` } type tfICMPMonitorFieldsV0 struct { @@ -324,6 +334,23 @@ func httpMonitorFieldsSchema() schema.Attribute { Computed: true, PlanModifiers: []planmodifier.List{listplanmodifier.UseStateForUnknown()}, }, + "ssl_certificate_authorities": schema.ListAttribute{ + ElementType: types.StringType, + Optional: true, + MarkdownDescription: "The list of root certificates for verifications is required.", + }, + "ssl_certificate": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Certificate.", + }, + "ssl_key": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Certificate key.", + }, + "ssl_key_passphrase": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Key passphrase.", + }, "max_redirects": schema.Int64Attribute{ Optional: true, MarkdownDescription: "The maximum number of redirects to follow. Default: `0`", @@ -395,6 +422,23 @@ func tcpMonitorFieldsSchema() schema.Attribute { Computed: true, PlanModifiers: []planmodifier.List{listplanmodifier.UseStateForUnknown()}, }, + "ssl_certificate_authorities": schema.ListAttribute{ + ElementType: types.StringType, + Optional: true, + MarkdownDescription: "The list of root certificates for verifications is required.", + }, + "ssl_certificate": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Certificate.", + }, + "ssl_key": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Certificate key.", + }, + "ssl_key_passphrase": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Key passphrase.", + }, "check_send": schema.StringAttribute{ Optional: true, MarkdownDescription: "An optional payload string to send to the remote host.", @@ -616,9 +660,12 @@ func (v *tfTCPMonitorFieldsV0) toTfTCPMonitorFieldsV0(ctx context.Context, dg di return nil } return &tfTCPMonitorFieldsV0{ - Host: types.StringValue(api.Host), + Host: types.StringValue(api.Host), + + //TODO: SslVerificationMode: types.StringValue(api.SslVerificationMode), SslSupportedProtocols: sslSupportedProtocols, + CheckSend: checkSend, CheckReceive: checkReceive, ProxyURL: types.StringValue(api.ProxyUrl), @@ -700,19 +747,22 @@ func (v *tfHTTPMonitorFieldsV0) toTfHTTPMonitorFieldsV0(ctx context.Context, dg return nil } return &tfHTTPMonitorFieldsV0{ - URL: types.StringValue(api.Url), + URL: types.StringValue(api.Url), + + //TODO SslVerificationMode: types.StringValue(api.SslVerificationMode), SslSupportedProtocols: sslSupportedProtocols, - MaxRedirects: types.Int64Value(maxRedirects), - Mode: types.StringValue(string(api.Mode)), - IPv4: types.BoolPointerValue(api.Ipv4), - IPv6: types.BoolPointerValue(api.Ipv6), - Username: username, - Password: password, - ProxyHeader: proxyHeaders, - ProxyURL: types.StringValue(api.ProxyUrl), - Check: v.Check, - Response: v.Response, + + MaxRedirects: types.Int64Value(maxRedirects), + Mode: types.StringValue(string(api.Mode)), + IPv4: types.BoolPointerValue(api.Ipv4), + IPv6: types.BoolPointerValue(api.Ipv6), + Username: username, + Password: password, + ProxyHeader: proxyHeaders, + ProxyURL: types.StringValue(api.ProxyUrl), + Check: v.Check, + Response: v.Response, } } @@ -805,57 +855,84 @@ func tfInt64ToString(v types.Int64) string { } func (v *tfModelV0) toHttpMonitorFields(ctx context.Context) (kbapi.MonitorFields, diag.Diagnostics) { - proxyHeaders, dg := toJsonObject(v.HTTP.ProxyHeader) + http := v.HTTP + proxyHeaders, dg := toJsonObject(http.ProxyHeader) if dg.HasError() { return nil, dg } - response, dg := toJsonObject(v.HTTP.Response) + response, dg := toJsonObject(http.Response) if dg.HasError() { return nil, dg } - check, dg := toJsonObject(v.HTTP.Check) + check, dg := toJsonObject(http.Check) if dg.HasError() { return nil, dg } - sslSupportedProtocols := utils.ListTypeToSlice_String(ctx, v.HTTP.SslSupportedProtocols, path.Root("http").AtName("ssl_supported_protocols"), &dg) - if dg.HasError() { - return nil, dg + var ssl *kbapi.SSLConfig + if !(http.SslSupportedProtocols.IsNull() || http.SslSupportedProtocols.IsUnknown()) { + sslSupportedProtocols := utils.ListTypeToSlice_String(ctx, http.SslSupportedProtocols, path.Root("http").AtName("ssl_supported_protocols"), &dg) + if dg.HasError() { + return nil, dg + } + ssl = &kbapi.SSLConfig{} + ssl.SupportedProtocols = sslSupportedProtocols } - maxRedirects := tfInt64ToString(v.HTTP.MaxRedirects) + if !(http.SslVerificationMode.IsNull() || http.SslVerificationMode.IsUnknown()) { + if ssl == nil { + ssl = &kbapi.SSLConfig{} + } + ssl.VerificationMode = http.SslVerificationMode.ValueString() + } + + maxRedirects := tfInt64ToString(http.MaxRedirects) return kbapi.HTTPMonitorFields{ - Url: v.HTTP.URL.ValueString(), - SslVerificationMode: v.HTTP.SslVerificationMode.ValueString(), - SslSupportedProtocols: sslSupportedProtocols, - MaxRedirects: maxRedirects, - Mode: kbapi.HttpMonitorMode(v.HTTP.Mode.ValueString()), - Ipv4: v.HTTP.IPv4.ValueBoolPointer(), - Ipv6: v.HTTP.IPv6.ValueBoolPointer(), - Username: v.HTTP.Username.ValueString(), - Password: v.HTTP.Password.ValueString(), - ProxyHeader: proxyHeaders, - ProxyUrl: v.HTTP.ProxyURL.ValueString(), - Response: response, - Check: check, + Url: http.URL.ValueString(), + Ssl: ssl, + MaxRedirects: maxRedirects, + Mode: kbapi.HttpMonitorMode(http.Mode.ValueString()), + Ipv4: http.IPv4.ValueBoolPointer(), + Ipv6: http.IPv6.ValueBoolPointer(), + Username: http.Username.ValueString(), + Password: http.Password.ValueString(), + ProxyHeader: proxyHeaders, + ProxyUrl: http.ProxyURL.ValueString(), + Response: response, + Check: check, }, dg } func (v *tfModelV0) toTCPMonitorFields(ctx context.Context) (kbapi.MonitorFields, diag.Diagnostics) { + + tcp := v.TCP + dg := diag.Diagnostics{} - sslSupportedProtocols := utils.ListTypeToSlice_String(ctx, v.TCP.SslSupportedProtocols, path.Root("tcp").AtName("ssl_supported_protocols"), &dg) - if dg.HasError() { - return nil, dg + var ssl *kbapi.SSLConfig + if !(tcp.SslSupportedProtocols.IsNull() || tcp.SslSupportedProtocols.IsUnknown()) { + sslSupportedProtocols := utils.ListTypeToSlice_String(ctx, tcp.SslSupportedProtocols, path.Root("tcp").AtName("ssl_supported_protocols"), &dg) + if dg.HasError() { + return nil, dg + } + ssl = &kbapi.SSLConfig{} + ssl.SupportedProtocols = sslSupportedProtocols } + if !(tcp.SslVerificationMode.IsNull() || tcp.SslVerificationMode.IsUnknown()) { + if ssl == nil { + ssl = &kbapi.SSLConfig{} + } + ssl.VerificationMode = tcp.SslVerificationMode.ValueString() + } + //TODO: ssl fields + return kbapi.TCPMonitorFields{ - Host: v.TCP.Host.ValueString(), - SslVerificationMode: v.TCP.SslVerificationMode.ValueString(), - SslSupportedProtocols: sslSupportedProtocols, - CheckSend: v.TCP.CheckSend.ValueString(), - CheckReceive: v.TCP.CheckReceive.ValueString(), - ProxyUrl: v.TCP.ProxyURL.ValueString(), - ProxyUseLocalResolver: v.TCP.ProxyUseLocalResolver.ValueBoolPointer(), + Host: tcp.Host.ValueString(), + CheckSend: tcp.CheckSend.ValueString(), + CheckReceive: tcp.CheckReceive.ValueString(), + ProxyUrl: tcp.ProxyURL.ValueString(), + ProxyUseLocalResolver: tcp.ProxyUseLocalResolver.ValueBoolPointer(), + Ssl: ssl, }, dg } diff --git a/internal/kibana/synthetics/schema_test.go b/internal/kibana/synthetics/schema_test.go index 509d9fb12..74f0042fb 100644 --- a/internal/kibana/synthetics/schema_test.go +++ b/internal/kibana/synthetics/schema_test.go @@ -45,6 +45,7 @@ func TestToModelV0(t *testing.T) { HTTP: &tfHTTPMonitorFieldsV0{ URL: types.StringValue(""), SslVerificationMode: types.StringValue(""), + SslSupportedProtocols: types.ListNull(types.StringType), MaxRedirects: types.Int64Value(0), Mode: types.StringValue(""), Username: types.StringValue(""), @@ -53,7 +54,6 @@ func TestToModelV0(t *testing.T) { ProxyURL: types.StringValue(""), Response: jsontypes.NewNormalizedValue("null"), Check: jsontypes.NewNormalizedValue("null"), - SslSupportedProtocols: types.ListNull(types.StringType), }, }, }, @@ -73,10 +73,10 @@ func TestToModelV0(t *testing.T) { TCP: &tfTCPMonitorFieldsV0{ Host: types.StringValue(""), SslVerificationMode: types.StringValue(""), + SslSupportedProtocols: types.ListNull(types.StringType), CheckSend: types.StringValue(""), CheckReceive: types.StringValue(""), ProxyURL: types.StringValue(""), - SslSupportedProtocols: types.ListNull(types.StringType), }, }, }, @@ -456,19 +456,21 @@ func TestToKibanaAPIRequest(t *testing.T) { Params: kbapi.JsonObject{"param1": "value1"}, }, fields: kbapi.HTTPMonitorFields{ - Url: "https://example.com", - SslVerificationMode: "full", - SslSupportedProtocols: []string{"TLSv1.2", "TLSv1.3"}, - MaxRedirects: "5", - Mode: "all", - Ipv4: tBool, - Ipv6: fBool, - Username: "user", - Password: "pass", - ProxyHeader: kbapi.JsonObject{"header1": "value1"}, - ProxyUrl: "https://proxy.com", - Response: kbapi.JsonObject{"response1": "value1"}, - Check: kbapi.JsonObject{"check1": "value1"}, + Url: "https://example.com", + Ssl: &kbapi.SSLConfig{ + VerificationMode: "full", + SupportedProtocols: []string{"TLSv1.2", "TLSv1.3"}, + }, + MaxRedirects: "5", + Mode: "all", + Ipv4: tBool, + Ipv6: fBool, + Username: "user", + Password: "pass", + ProxyHeader: kbapi.JsonObject{"header1": "value1"}, + ProxyUrl: "https://proxy.com", + Response: kbapi.JsonObject{"response1": "value1"}, + Check: kbapi.JsonObject{"check1": "value1"}, }, }, }, @@ -514,9 +516,11 @@ func TestToKibanaAPIRequest(t *testing.T) { Params: kbapi.JsonObject{"param1": "value1"}, }, fields: kbapi.TCPMonitorFields{ - Host: "example.com:9200", - SslVerificationMode: "full", - SslSupportedProtocols: []string{"TLSv1.2", "TLSv1.3"}, + Host: "example.com:9200", + Ssl: &kbapi.SSLConfig{ + VerificationMode: "full", + SupportedProtocols: []string{"TLSv1.2", "TLSv1.3"}, + }, CheckSend: "hello", CheckReceive: "world", ProxyUrl: "http://proxy.com", @@ -700,10 +704,10 @@ func TestToModelV0MergeAttributes(t *testing.T) { Locations: []types.String{types.StringValue("us_east")}, TCP: &tfTCPMonitorFieldsV0{ Host: types.StringValue(""), - SslVerificationMode: types.StringValue(""), CheckSend: types.StringValue("hello"), CheckReceive: types.StringValue("world"), ProxyURL: types.StringValue(""), + SslVerificationMode: types.StringValue(""), SslSupportedProtocols: types.ListNull(types.StringType), }, }, diff --git a/libs/go-kibana-rest/kbapi/api.kibana_synthetics.go b/libs/go-kibana-rest/kbapi/api.kibana_synthetics.go index 590e3dcf4..c80c7cbb0 100644 --- a/libs/go-kibana-rest/kbapi/api.kibana_synthetics.go +++ b/libs/go-kibana-rest/kbapi/api.kibana_synthetics.go @@ -109,31 +109,36 @@ type BrowserMonitorFields struct { } type TCPMonitorFields struct { - Host string `json:"host"` - //TODO: support certificate_authorities, certificate, key, key_passphrase - SslVerificationMode string `json:"ssl.verification_mode,omitempty"` - SslSupportedProtocols []string `json:"ssl.supported_protocols,omitempty"` - CheckSend string `json:"check.send,omitempty"` - CheckReceive string `json:"check.receive,omitempty"` - ProxyUrl string `json:"proxy_url,omitempty"` - ProxyUseLocalResolver *bool `json:"proxy_use_local_resolver,omitempty"` + Host string `json:"host"` + Ssl *SSLConfig `json:"ssl,omitempty"` + CheckSend string `json:"check.send,omitempty"` + CheckReceive string `json:"check.receive,omitempty"` + ProxyUrl string `json:"proxy_url,omitempty"` + ProxyUseLocalResolver *bool `json:"proxy_use_local_resolver,omitempty"` +} + +type SSLConfig struct { + VerificationMode string `json:"verification_mode,omitempty"` + SupportedProtocols []string `json:"supported_protocols,omitempty"` + CertificateAuthorities []string `json:"certificate_authorities,omitempty"` + Certificate string `json:"certificate,omitempty"` + Key string `json:"key,omitempty"` + KeyPassphrase string `json:"key_passphrase,omitempty"` } type HTTPMonitorFields struct { - Url string `json:"url"` - //TODO: support certificate_authorities, certificate, key, key_passphrase - SslVerificationMode string `json:"ssl.verification_mode,omitempty"` - SslSupportedProtocols []string `json:"ssl.supported_protocols,omitempty"` - MaxRedirects string `json:"max_redirects,omitempty"` - Mode HttpMonitorMode `json:"mode,omitempty"` - Ipv4 *bool `json:"ipv4,omitempty"` - Ipv6 *bool `json:"ipv6,omitempty"` - Username string `json:"username,omitempty"` - Password string `json:"password,omitempty"` - ProxyHeader JsonObject `json:"proxy_headers,omitempty"` - ProxyUrl string `json:"proxy_url,omitempty"` - Response JsonObject `json:"response,omitempty"` - Check JsonObject `json:"check,omitempty"` + Url string `json:"url"` + Ssl *SSLConfig `json:"ssl,omitempty"` + MaxRedirects string `json:"max_redirects,omitempty"` + Mode HttpMonitorMode `json:"mode,omitempty"` + Ipv4 *bool `json:"ipv4,omitempty"` + Ipv6 *bool `json:"ipv6,omitempty"` + Username string `json:"username,omitempty"` + Password string `json:"password,omitempty"` + ProxyHeader JsonObject `json:"proxy_headers,omitempty"` + ProxyUrl string `json:"proxy_url,omitempty"` + Response JsonObject `json:"response,omitempty"` + Check JsonObject `json:"check,omitempty"` } type SyntheticsMonitorConfig struct { @@ -224,12 +229,13 @@ type SyntheticsMonitor struct { CheckRequestHeaders JsonObject `json:"check.request.headers,omitempty"` CheckRequestMethod string `json:"check.request.method,omitempty"` //http and tcp - ProxyUrl string `json:"proxy_url,omitempty"` - //TODO: support certificate_authorities, certificate, key, key_passphrase - - SslVerificationMode string `json:"ssl.verification_mode"` - SslSupportedProtocols []string `json:"ssl.supported_protocols"` - + ProxyUrl string `json:"proxy_url,omitempty"` + SslVerificationMode string `json:"ssl.verification_mode"` + SslSupportedProtocols []string `json:"ssl.supported_protocols"` + SslCertificateAuthorities []string `json:"ssl.certificate_authorities,omitempty"` + SslCertificate string `json:"ssl.certificate,omitempty"` + SslKey string `json:"ssl.key,omitempty"` + SslKeyPassphrase string `json:"ssl.key_passphrase,omitempty"` //tcp and icmp Host string `json:"host,omitempty"` //tcp diff --git a/libs/go-kibana-rest/kbapi/api.kibana_synthetics_test.go b/libs/go-kibana-rest/kbapi/api.kibana_synthetics_test.go index 8bf8386ad..4cebddacb 100644 --- a/libs/go-kibana-rest/kbapi/api.kibana_synthetics_test.go +++ b/libs/go-kibana-rest/kbapi/api.kibana_synthetics_test.go @@ -146,18 +146,15 @@ func (s *KBAPITestSuite) TestKibanaSyntheticsMonitorAPI() { RetestOnFailure: f, }, fields: HTTPMonitorFields{ - Url: "http://localhost:5601", - SslSupportedProtocols: []string{"TLSv1.0", "TLSv1.1", "TLSv1.2"}, - SslVerificationMode: "full", - //Ssl: map[string]interface{}{ - // "verification_mode": "full", - // "supported_protocols": []string{"TLSv1.0", "TLSv1.1", "TLSv1.2"}, - // - // "certificate_authorities": []string{"ca1", "ca2"}, - // "certificate": "cert", - // "key": "key", - // "key_passphrase": "passphrase", - //}, + Url: "http://localhost:5601", + Ssl: &SSLConfig{ + VerificationMode: "full", + SupportedProtocols: []string{"TLSv1.0", "TLSv1.1", "TLSv1.2"}, + CertificateAuthorities: []string{"ca1", "ca2"}, + Certificate: "cert", + Key: "key", + KeyPassphrase: "passphrase", + }, MaxRedirects: "2", Mode: ModeAny, Ipv4: t, @@ -223,9 +220,15 @@ func (s *KBAPITestSuite) TestKibanaSyntheticsMonitorAPI() { RetestOnFailure: f, }, fields: TCPMonitorFields{ - Host: "localhost:5601", - SslSupportedProtocols: []string{"TLSv1.0", "TLSv1.1", "TLSv1.2"}, - SslVerificationMode: "full", + Host: "localhost:5601", + Ssl: &SSLConfig{ + VerificationMode: "full", + SupportedProtocols: []string{"TLSv1.0", "TLSv1.1", "TLSv1.2"}, + CertificateAuthorities: []string{"ca1", "ca2"}, + Certificate: "cert", + Key: "key", + KeyPassphrase: "passphrase", + }, ProxyUseLocalResolver: t, ProxyUrl: "http://localhost", CheckSend: "Hello World", From ca258de15005ae458d553fe85cd96954817215d5 Mon Sep 17 00:00:00 2001 From: Boris Ilyushonak Date: Fri, 20 Dec 2024 15:01:53 +0100 Subject: [PATCH 09/13] add ssl fields to tcp / http monitors --- CONTRIBUTING.md | 5 + internal/kibana/synthetics/acc_test.go | 42 +++-- internal/kibana/synthetics/schema.go | 154 +++++++++++------- internal/kibana/synthetics/schema_test.go | 183 ++++++++++++++-------- 4 files changed, 250 insertions(+), 134 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6ee58a789..9c69b9d6d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -38,6 +38,11 @@ Format the code before pushing: make fmt ``` +Check if the linting: +```bash +make lint +``` + Create a PR and check acceptance test matrix is green. ## Run provider with local terraform diff --git a/internal/kibana/synthetics/acc_test.go b/internal/kibana/synthetics/acc_test.go index 7683f0de6..6d4a89f46 100644 --- a/internal/kibana/synthetics/acc_test.go +++ b/internal/kibana/synthetics/acc_test.go @@ -16,14 +16,6 @@ var ( kibana816Version = version.Must(version.NewVersion("8.16.0")) ) -/* -TODOs: -- [ ] TF schema - fix https://github.com/elastic/terraform-provider-elasticstack/issues/965 -- [ ] TF schema - fix https://github.com/elastic/terraform-provider-elasticstack/issues/916 -- [x] TF schema - test imports after 8.16 fixes -- [ ] Update change log -*/ - const ( httpMonitorMinConfig = ` @@ -129,6 +121,25 @@ resource "elasticstack_kibana_synthetics_monitor" "%s" { retest_on_failure = false } +` + + tcpMonitorMinConfig = ` + +resource "elasticstack_kibana_synthetics_monitor" "%s" { + name = "TestTcpMonitorResource - %s" + private_locations = [elasticstack_kibana_synthetics_private_location.%s.label] + alert = { + status = { + enabled = true + } + tls = { + enabled = true + } + } + tcp = { + host = "http://localhost:5601" + } +} ` tcpMonitorConfig = ` @@ -411,11 +422,24 @@ func TestSyntheticMonitorTCPResource(t *testing.T) { tcpMonitorId, config := testMonitorConfig(id, tcpMonitorConfig, name) _, configUpdated := testMonitorConfig(id, tcpMonitorUpdated, name) + bmName := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum) + bmTcponitorId, bmConfig := testMonitorConfig("tcp-monitor-min", tcpMonitorMinConfig, bmName) + resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.Providers, Steps: []resource.TestStep{ - + // Create and Read tcp monitor with minimum fields + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minKibanaVersion), + Config: bmConfig, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet(bmTcponitorId, "id"), + resource.TestCheckResourceAttr(bmTcponitorId, "name", "TestTcpMonitorResource - "+bmName), + resource.TestCheckResourceAttr(bmTcponitorId, "space_id", "default"), + resource.TestCheckResourceAttr(bmTcponitorId, "tcp.host", "http://localhost:5601"), + ), + }, // Create and Read tcp monitor { SkipFunc: versionutils.CheckIfVersionIsUnsupported(minKibanaVersion), diff --git a/internal/kibana/synthetics/schema.go b/internal/kibana/synthetics/schema.go index 8ae1ae174..08dd95137 100644 --- a/internal/kibana/synthetics/schema.go +++ b/internal/kibana/synthetics/schema.go @@ -42,6 +42,15 @@ type tfAlertConfigV0 struct { TLS *tfStatusConfigV0 `tfsdk:"tls"` } +type tfSSLConfig struct { + SslVerificationMode types.String `tfsdk:"ssl_verification_mode"` + SslSupportedProtocols types.List `tfsdk:"ssl_supported_protocols"` + SslCertificateAuthorities []types.String `tfsdk:"ssl_certificate_authorities"` + SslCertificate types.String `tfsdk:"ssl_certificate"` + SslKey types.String `tfsdk:"ssl_key"` + SslKeyPassphrase types.String `tfsdk:"ssl_key_passphrase"` +} + type tfHTTPMonitorFieldsV0 struct { URL types.String `tfsdk:"url"` MaxRedirects types.Int64 `tfsdk:"max_redirects"` @@ -55,12 +64,7 @@ type tfHTTPMonitorFieldsV0 struct { Response jsontypes.Normalized `tfsdk:"response"` Check jsontypes.Normalized `tfsdk:"check"` - SslVerificationMode types.String `tfsdk:"ssl_verification_mode"` - SslSupportedProtocols types.List `tfsdk:"ssl_supported_protocols"` - SslCertificateAuthorities []types.String `tfsdk:"ssl_certificate_authorities"` - SslCertificate types.String `tfsdk:"ssl_certificate"` - SslKey types.String `tfsdk:"ssl_key"` - SslKeyPassphrase types.String `tfsdk:"ssl_key_passphrase"` + tfSSLConfig } type tfTCPMonitorFieldsV0 struct { @@ -70,12 +74,7 @@ type tfTCPMonitorFieldsV0 struct { ProxyURL types.String `tfsdk:"proxy_url"` ProxyUseLocalResolver types.Bool `tfsdk:"proxy_use_local_resolver"` - SslVerificationMode types.String `tfsdk:"ssl_verification_mode"` - SslSupportedProtocols types.List `tfsdk:"ssl_supported_protocols"` - SslCertificateAuthorities []types.String `tfsdk:"ssl_certificate_authorities"` - SslCertificate types.String `tfsdk:"ssl_certificate"` - SslKey types.String `tfsdk:"ssl_key"` - SslKeyPassphrase types.String `tfsdk:"ssl_key_passphrase"` + tfSSLConfig } type tfICMPMonitorFieldsV0 struct { @@ -342,14 +341,20 @@ func httpMonitorFieldsSchema() schema.Attribute { "ssl_certificate": schema.StringAttribute{ Optional: true, MarkdownDescription: "Certificate.", + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, }, "ssl_key": schema.StringAttribute{ Optional: true, MarkdownDescription: "Certificate key.", + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, }, "ssl_key_passphrase": schema.StringAttribute{ Optional: true, MarkdownDescription: "Key passphrase.", + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, }, "max_redirects": schema.Int64Attribute{ Optional: true, @@ -430,14 +435,20 @@ func tcpMonitorFieldsSchema() schema.Attribute { "ssl_certificate": schema.StringAttribute{ Optional: true, MarkdownDescription: "Certificate.", + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, }, "ssl_key": schema.StringAttribute{ Optional: true, MarkdownDescription: "Certificate key.", + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, }, "ssl_key_passphrase": schema.StringAttribute{ Optional: true, MarkdownDescription: "Key passphrase.", + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, }, "check_send": schema.StringAttribute{ Optional: true, @@ -456,6 +467,8 @@ func tcpMonitorFieldsSchema() schema.Attribute { "proxy_use_local_resolver": schema.BoolAttribute{ Optional: true, MarkdownDescription: " A Boolean value that determines whether hostnames are resolved locally instead of being resolved on the proxy server. The default value is false, which means that name resolution occurs on the proxy server.", + Computed: true, + PlanModifiers: []planmodifier.Bool{boolplanmodifier.UseStateForUnknown()}, }, }, } @@ -660,16 +673,19 @@ func (v *tfTCPMonitorFieldsV0) toTfTCPMonitorFieldsV0(ctx context.Context, dg di return nil } return &tfTCPMonitorFieldsV0{ - Host: types.StringValue(api.Host), - - //TODO: - SslVerificationMode: types.StringValue(api.SslVerificationMode), - SslSupportedProtocols: sslSupportedProtocols, - + Host: types.StringValue(api.Host), CheckSend: checkSend, CheckReceive: checkReceive, ProxyURL: types.StringValue(api.ProxyUrl), ProxyUseLocalResolver: types.BoolPointerValue(api.ProxyUseLocalResolver), + tfSSLConfig: tfSSLConfig{ + SslVerificationMode: types.StringValue(api.SslVerificationMode), + SslSupportedProtocols: sslSupportedProtocols, + SslCertificateAuthorities: StringSliceValue(api.SslCertificateAuthorities), + SslCertificate: types.StringValue(api.SslCertificate), + SslKey: types.StringValue(api.SslKey), + SslKeyPassphrase: types.StringValue(api.SslKeyPassphrase), + }, } } @@ -741,18 +757,14 @@ func (v *tfHTTPMonitorFieldsV0) toTfHTTPMonitorFieldsV0(ctx context.Context, dg return nil } + //TODO: DRY with TCP sslSupportedProtocols := utils.SliceToListType_String(ctx, api.SslSupportedProtocols, path.Root("http").AtName("ssl_supported_protocols"), &dg) if dg.HasError() { return nil } return &tfHTTPMonitorFieldsV0{ - URL: types.StringValue(api.Url), - - //TODO - SslVerificationMode: types.StringValue(api.SslVerificationMode), - SslSupportedProtocols: sslSupportedProtocols, - + URL: types.StringValue(api.Url), MaxRedirects: types.Int64Value(maxRedirects), Mode: types.StringValue(string(api.Mode)), IPv4: types.BoolPointerValue(api.Ipv4), @@ -763,6 +775,15 @@ func (v *tfHTTPMonitorFieldsV0) toTfHTTPMonitorFieldsV0(ctx context.Context, dg ProxyURL: types.StringValue(api.ProxyUrl), Check: v.Check, Response: v.Response, + + tfSSLConfig: tfSSLConfig{ + SslVerificationMode: types.StringValue(api.SslVerificationMode), + SslSupportedProtocols: sslSupportedProtocols, + SslCertificateAuthorities: StringSliceValue(api.SslCertificateAuthorities), + SslCertificate: types.StringValue(api.SslCertificate), + SslKey: types.StringValue(api.SslKey), + SslKeyPassphrase: types.StringValue(api.SslKeyPassphrase), + }, } } @@ -854,6 +875,56 @@ func tfInt64ToString(v types.Int64) string { return res } +func toSSLConfig(ctx context.Context, dg diag.Diagnostics, v tfSSLConfig, p string) (*kbapi.SSLConfig, diag.Diagnostics) { + + var ssl *kbapi.SSLConfig + if !(v.SslSupportedProtocols.IsNull() || v.SslSupportedProtocols.IsUnknown()) { + sslSupportedProtocols := utils.ListTypeToSlice_String(ctx, v.SslSupportedProtocols, path.Root(p).AtName("ssl_supported_protocols"), &dg) + if dg.HasError() { + return nil, dg + } + ssl = &kbapi.SSLConfig{} + ssl.SupportedProtocols = sslSupportedProtocols + } + + if !(v.SslVerificationMode.IsNull() || v.SslVerificationMode.IsUnknown()) { + if ssl == nil { + ssl = &kbapi.SSLConfig{} + } + ssl.VerificationMode = v.SslVerificationMode.ValueString() + } + + certAuths := ValueStringSlice(v.SslCertificateAuthorities) + if len(certAuths) > 0 { + if ssl == nil { + ssl = &kbapi.SSLConfig{} + } + ssl.CertificateAuthorities = certAuths + } + + if !(v.SslCertificate.IsUnknown() || v.SslCertificate.IsNull()) { + if ssl == nil { + ssl = &kbapi.SSLConfig{} + } + ssl.Certificate = v.SslCertificate.ValueString() + } + + if !(v.SslKey.IsUnknown() || v.SslKey.IsNull()) { + if ssl == nil { + ssl = &kbapi.SSLConfig{} + } + ssl.Key = v.SslKey.ValueString() + } + + if !(v.SslKeyPassphrase.IsUnknown() || v.SslKeyPassphrase.IsNull()) { + if ssl == nil { + ssl = &kbapi.SSLConfig{} + } + ssl.KeyPassphrase = v.SslKeyPassphrase.ValueString() + } + return ssl, dg +} + func (v *tfModelV0) toHttpMonitorFields(ctx context.Context) (kbapi.MonitorFields, diag.Diagnostics) { http := v.HTTP proxyHeaders, dg := toJsonObject(http.ProxyHeader) @@ -869,22 +940,7 @@ func (v *tfModelV0) toHttpMonitorFields(ctx context.Context) (kbapi.MonitorField return nil, dg } - var ssl *kbapi.SSLConfig - if !(http.SslSupportedProtocols.IsNull() || http.SslSupportedProtocols.IsUnknown()) { - sslSupportedProtocols := utils.ListTypeToSlice_String(ctx, http.SslSupportedProtocols, path.Root("http").AtName("ssl_supported_protocols"), &dg) - if dg.HasError() { - return nil, dg - } - ssl = &kbapi.SSLConfig{} - ssl.SupportedProtocols = sslSupportedProtocols - } - - if !(http.SslVerificationMode.IsNull() || http.SslVerificationMode.IsUnknown()) { - if ssl == nil { - ssl = &kbapi.SSLConfig{} - } - ssl.VerificationMode = http.SslVerificationMode.ValueString() - } + ssl, dg := toSSLConfig(ctx, dg, http.tfSSLConfig, "http") maxRedirects := tfInt64ToString(http.MaxRedirects) return kbapi.HTTPMonitorFields{ @@ -908,23 +964,7 @@ func (v *tfModelV0) toTCPMonitorFields(ctx context.Context) (kbapi.MonitorFields tcp := v.TCP dg := diag.Diagnostics{} - var ssl *kbapi.SSLConfig - if !(tcp.SslSupportedProtocols.IsNull() || tcp.SslSupportedProtocols.IsUnknown()) { - sslSupportedProtocols := utils.ListTypeToSlice_String(ctx, tcp.SslSupportedProtocols, path.Root("tcp").AtName("ssl_supported_protocols"), &dg) - if dg.HasError() { - return nil, dg - } - ssl = &kbapi.SSLConfig{} - ssl.SupportedProtocols = sslSupportedProtocols - } - - if !(tcp.SslVerificationMode.IsNull() || tcp.SslVerificationMode.IsUnknown()) { - if ssl == nil { - ssl = &kbapi.SSLConfig{} - } - ssl.VerificationMode = tcp.SslVerificationMode.ValueString() - } - //TODO: ssl fields + ssl, dg := toSSLConfig(ctx, dg, tcp.tfSSLConfig, "tcp") return kbapi.TCPMonitorFields{ Host: tcp.Host.ValueString(), diff --git a/internal/kibana/synthetics/schema_test.go b/internal/kibana/synthetics/schema_test.go index 74f0042fb..48a999ef6 100644 --- a/internal/kibana/synthetics/schema_test.go +++ b/internal/kibana/synthetics/schema_test.go @@ -43,17 +43,23 @@ func TestToModelV0(t *testing.T) { TimeoutSeconds: types.Int64Value(0), Params: jsontypes.NewNormalizedValue("null"), HTTP: &tfHTTPMonitorFieldsV0{ - URL: types.StringValue(""), - SslVerificationMode: types.StringValue(""), - SslSupportedProtocols: types.ListNull(types.StringType), - MaxRedirects: types.Int64Value(0), - Mode: types.StringValue(""), - Username: types.StringValue(""), - Password: types.StringValue(""), - ProxyHeader: jsontypes.NewNormalizedValue("null"), - ProxyURL: types.StringValue(""), - Response: jsontypes.NewNormalizedValue("null"), - Check: jsontypes.NewNormalizedValue("null"), + URL: types.StringValue(""), + MaxRedirects: types.Int64Value(0), + Mode: types.StringValue(""), + Username: types.StringValue(""), + Password: types.StringValue(""), + ProxyHeader: jsontypes.NewNormalizedValue("null"), + ProxyURL: types.StringValue(""), + Response: jsontypes.NewNormalizedValue("null"), + Check: jsontypes.NewNormalizedValue("null"), + + tfSSLConfig: tfSSLConfig{ + SslVerificationMode: types.StringValue(""), + SslSupportedProtocols: types.ListNull(types.StringType), + SslCertificate: types.StringValue(""), + SslKey: types.StringValue(""), + SslKeyPassphrase: types.StringValue(""), + }, }, }, }, @@ -71,12 +77,17 @@ func TestToModelV0(t *testing.T) { TimeoutSeconds: types.Int64Value(0), Params: jsontypes.NewNormalizedValue("null"), TCP: &tfTCPMonitorFieldsV0{ - Host: types.StringValue(""), - SslVerificationMode: types.StringValue(""), - SslSupportedProtocols: types.ListNull(types.StringType), - CheckSend: types.StringValue(""), - CheckReceive: types.StringValue(""), - ProxyURL: types.StringValue(""), + Host: types.StringValue(""), + CheckSend: types.StringValue(""), + CheckReceive: types.StringValue(""), + ProxyURL: types.StringValue(""), + tfSSLConfig: tfSSLConfig{ + SslVerificationMode: types.StringValue(""), + SslSupportedProtocols: types.ListNull(types.StringType), + SslCertificate: types.StringValue(""), + SslKey: types.StringValue(""), + SslKeyPassphrase: types.StringValue(""), + }, }, }, }, @@ -160,6 +171,10 @@ func TestToModelV0(t *testing.T) { CheckRequestMethod: "POST", SslVerificationMode: "full", SslSupportedProtocols: []string{"TLSv1.2", "TLSv1.3"}, + SslCertificateAuthorities: []string{"cert1", "cert2"}, + SslCertificate: "cert", + SslKey: "key", + SslKeyPassphrase: "passphrase", }, expected: tfModelV0{ ID: types.StringValue("default/test-id-http"), @@ -175,11 +190,7 @@ func TestToModelV0(t *testing.T) { TimeoutSeconds: types.Int64Value(30), Params: jsontypes.NewNormalizedValue(`{"param1":"value1"}`), HTTP: &tfHTTPMonitorFieldsV0{ - URL: types.StringValue("https://example.com"), - SslVerificationMode: types.StringValue("full"), - SslSupportedProtocols: types.ListValueMust(types.StringType, []attr.Value{ - types.StringValue("TLSv1.2"), types.StringValue("TLSv1.3"), - }), + URL: types.StringValue("https://example.com"), MaxRedirects: types.Int64Value(5), Mode: types.StringValue("all"), IPv4: types.BoolPointerValue(tBool), @@ -188,6 +199,17 @@ func TestToModelV0(t *testing.T) { Password: types.StringValue("pass"), ProxyHeader: jsontypes.NewNormalizedValue(`{"header1":"value1"}`), ProxyURL: types.StringValue("https://proxy.com"), + + tfSSLConfig: tfSSLConfig{ + SslVerificationMode: types.StringValue("full"), + SslSupportedProtocols: types.ListValueMust(types.StringType, []attr.Value{ + types.StringValue("TLSv1.2"), types.StringValue("TLSv1.3"), + }), + SslCertificateAuthorities: []types.String{types.StringValue("cert1"), types.StringValue("cert2")}, + SslCertificate: types.StringValue("cert"), + SslKey: types.StringValue("key"), + SslKeyPassphrase: types.StringValue("passphrase"), + }, }, }, }, @@ -206,19 +228,23 @@ func TestToModelV0(t *testing.T) { Locations: []kbapi.MonitorLocationConfig{ {Label: "test private location", IsServiceManaged: false}, }, - Origin: "origin", - Params: kbapi.JsonObject{"param1": "value1"}, - MaxAttempts: 3, - Revision: 1, - Ui: kbapi.JsonObject{"is_tls_enabled": false}, - Type: kbapi.Tcp, - SslVerificationMode: "full", - SslSupportedProtocols: []string{"TLSv1.2", "TLSv1.3"}, - ProxyUrl: "http://proxy.com", - Host: "example.com:9200", - CheckSend: "hello", - CheckReceive: "world", - ProxyUseLocalResolver: tBool, + Origin: "origin", + Params: kbapi.JsonObject{"param1": "value1"}, + MaxAttempts: 3, + Revision: 1, + Ui: kbapi.JsonObject{"is_tls_enabled": false}, + Type: kbapi.Tcp, + SslVerificationMode: "full", + SslSupportedProtocols: []string{"TLSv1.2", "TLSv1.3"}, + SslCertificateAuthorities: []string{"cert1", "cert2"}, + SslCertificate: "cert", + SslKey: "key", + SslKeyPassphrase: "passphrase", + ProxyUrl: "http://proxy.com", + Host: "example.com:9200", + CheckSend: "hello", + CheckReceive: "world", + ProxyUseLocalResolver: tBool, }, expected: tfModelV0{ ID: types.StringValue("default/test-id-tcp"), @@ -234,15 +260,21 @@ func TestToModelV0(t *testing.T) { TimeoutSeconds: types.Int64Value(30), Params: jsontypes.NewNormalizedValue(`{"param1":"value1"}`), TCP: &tfTCPMonitorFieldsV0{ - Host: types.StringValue("example.com:9200"), - SslVerificationMode: types.StringValue("full"), - SslSupportedProtocols: types.ListValueMust(types.StringType, []attr.Value{ - types.StringValue("TLSv1.2"), types.StringValue("TLSv1.3"), - }), + Host: types.StringValue("example.com:9200"), CheckSend: types.StringValue("hello"), CheckReceive: types.StringValue("world"), ProxyURL: types.StringValue("http://proxy.com"), ProxyUseLocalResolver: types.BoolPointerValue(tBool), + tfSSLConfig: tfSSLConfig{ + SslVerificationMode: types.StringValue("full"), + SslSupportedProtocols: types.ListValueMust(types.StringType, []attr.Value{ + types.StringValue("TLSv1.2"), types.StringValue("TLSv1.3"), + }), + SslCertificateAuthorities: []types.String{types.StringValue("cert1"), types.StringValue("cert2")}, + SslCertificate: types.StringValue("cert"), + SslKey: types.StringValue("key"), + SslKeyPassphrase: types.StringValue("passphrase"), + }, }, }, }, @@ -424,11 +456,7 @@ func TestToKibanaAPIRequest(t *testing.T) { TimeoutSeconds: types.Int64Value(30), Params: jsontypes.NewNormalizedValue(`{"param1":"value1"}`), HTTP: &tfHTTPMonitorFieldsV0{ - URL: types.StringValue("https://example.com"), - SslVerificationMode: types.StringValue("full"), - SslSupportedProtocols: types.ListValueMust(types.StringType, []attr.Value{ - types.StringValue("TLSv1.2"), types.StringValue("TLSv1.3"), - }), + URL: types.StringValue("https://example.com"), MaxRedirects: types.Int64Value(5), Mode: types.StringValue("all"), IPv4: types.BoolPointerValue(tBool), @@ -439,6 +467,12 @@ func TestToKibanaAPIRequest(t *testing.T) { ProxyURL: types.StringValue("https://proxy.com"), Response: jsontypes.NewNormalizedValue(`{"response1":"value1"}`), Check: jsontypes.NewNormalizedValue(`{"check1":"value1"}`), + tfSSLConfig: tfSSLConfig{ //TODO: add fields + SslVerificationMode: types.StringValue("full"), + SslSupportedProtocols: types.ListValueMust(types.StringType, []attr.Value{ + types.StringValue("TLSv1.2"), types.StringValue("TLSv1.3"), + }), + }, }, }, expected: kibanaAPIRequest{ @@ -457,7 +491,7 @@ func TestToKibanaAPIRequest(t *testing.T) { }, fields: kbapi.HTTPMonitorFields{ Url: "https://example.com", - Ssl: &kbapi.SSLConfig{ + Ssl: &kbapi.SSLConfig{ //TODO VerificationMode: "full", SupportedProtocols: []string{"TLSv1.2", "TLSv1.3"}, }, @@ -490,11 +524,13 @@ func TestToKibanaAPIRequest(t *testing.T) { TimeoutSeconds: types.Int64Value(30), Params: jsontypes.NewNormalizedValue(`{"param1":"value1"}`), TCP: &tfTCPMonitorFieldsV0{ - Host: types.StringValue("example.com:9200"), - SslVerificationMode: types.StringValue("full"), - SslSupportedProtocols: types.ListValueMust(types.StringType, []attr.Value{ - types.StringValue("TLSv1.2"), types.StringValue("TLSv1.3"), - }), + Host: types.StringValue("example.com:9200"), + tfSSLConfig: tfSSLConfig{ //TODO: add fields + SslVerificationMode: types.StringValue("full"), + SslSupportedProtocols: types.ListValueMust(types.StringType, []attr.Value{ + types.StringValue("TLSv1.2"), types.StringValue("TLSv1.3"), + }), + }, CheckSend: types.StringValue("hello"), CheckReceive: types.StringValue("world"), ProxyURL: types.StringValue("http://proxy.com"), @@ -665,17 +701,23 @@ func TestToModelV0MergeAttributes(t *testing.T) { Params: jsontypes.NewNormalizedValue(`{"param1":"value1"}`), RetestOnFailure: types.BoolValue(true), HTTP: &tfHTTPMonitorFieldsV0{ - URL: types.StringValue(""), - SslVerificationMode: types.StringValue(""), - SslSupportedProtocols: types.ListNull(types.StringType), - MaxRedirects: types.Int64Value(0), - Mode: types.StringValue(""), - ProxyURL: types.StringValue(""), - ProxyHeader: jsontypes.NewNormalizedValue(`{"header1":"value1"}`), - Username: types.StringValue("test"), - Password: types.StringValue("password"), - Check: jsontypes.NewNormalizedValue(`{"check1":"value1"}`), - Response: jsontypes.NewNormalizedValue(`{"response1":"value1"}`), + URL: types.StringValue(""), + MaxRedirects: types.Int64Value(0), + Mode: types.StringValue(""), + ProxyURL: types.StringValue(""), + ProxyHeader: jsontypes.NewNormalizedValue(`{"header1":"value1"}`), + Username: types.StringValue("test"), + Password: types.StringValue("password"), + Check: jsontypes.NewNormalizedValue(`{"check1":"value1"}`), + Response: jsontypes.NewNormalizedValue(`{"response1":"value1"}`), + + tfSSLConfig: tfSSLConfig{ + SslVerificationMode: types.StringValue(""), + SslSupportedProtocols: types.ListNull(types.StringType), + SslCertificate: types.StringValue(""), + SslKey: types.StringValue(""), + SslKeyPassphrase: types.StringValue(""), + }, }, }, }, @@ -703,12 +745,17 @@ func TestToModelV0MergeAttributes(t *testing.T) { TimeoutSeconds: types.Int64Value(0), Locations: []types.String{types.StringValue("us_east")}, TCP: &tfTCPMonitorFieldsV0{ - Host: types.StringValue(""), - CheckSend: types.StringValue("hello"), - CheckReceive: types.StringValue("world"), - ProxyURL: types.StringValue(""), - SslVerificationMode: types.StringValue(""), - SslSupportedProtocols: types.ListNull(types.StringType), + Host: types.StringValue(""), + CheckSend: types.StringValue("hello"), + CheckReceive: types.StringValue("world"), + ProxyURL: types.StringValue(""), + tfSSLConfig: tfSSLConfig{ + SslVerificationMode: types.StringValue(""), + SslSupportedProtocols: types.ListNull(types.StringType), + SslCertificate: types.StringValue(""), + SslKey: types.StringValue(""), + SslKeyPassphrase: types.StringValue(""), + }, }, }, }, From 9ce7aba5aaac3ef7d7e2e59be7b628e975aa6525 Mon Sep 17 00:00:00 2001 From: Boris Ilyushonak Date: Fri, 20 Dec 2024 17:16:31 +0100 Subject: [PATCH 10/13] add tests --- internal/kibana/synthetics/acc_test.go | 197 ++++++++++++++++++++-- internal/kibana/synthetics/schema_test.go | 30 +++- 2 files changed, 209 insertions(+), 18 deletions(-) diff --git a/internal/kibana/synthetics/acc_test.go b/internal/kibana/synthetics/acc_test.go index 6d4a89f46..62b074098 100644 --- a/internal/kibana/synthetics/acc_test.go +++ b/internal/kibana/synthetics/acc_test.go @@ -61,6 +61,30 @@ resource "elasticstack_kibana_synthetics_monitor" "%s" { ipv6 = false } } +` + httpMonitorSslConfig = ` + +resource "elasticstack_kibana_synthetics_monitor" "%s" { + name = "TestHttpMonitorResource - %s" + private_locations = [elasticstack_kibana_synthetics_private_location.%s.label] + alert = { + status = { + enabled = true + } + tls = { + enabled = true + } + } + http = { + url = "http://localhost:5601" + ssl_verification_mode = "full" + ssl_supported_protocols = ["TLSv1.2"] + ssl_certificate_authorities = ["ca1", "ca2"] + ssl_certificate = "cert" + ssl_key = "key" + ssl_key_passphrase = "pass" + } +} ` httpMonitorUpdated = ` @@ -140,6 +164,31 @@ resource "elasticstack_kibana_synthetics_monitor" "%s" { host = "http://localhost:5601" } } +` + + tcpMonitorSslConfig = ` + +resource "elasticstack_kibana_synthetics_monitor" "%s" { + name = "TestHttpMonitorResource - %s" + private_locations = [elasticstack_kibana_synthetics_private_location.%s.label] + alert = { + status = { + enabled = true + } + tls = { + enabled = true + } + } + tcp = { + host = "http://localhost:5601" + ssl_verification_mode = "full" + ssl_supported_protocols = ["TLSv1.2"] + ssl_certificate_authorities = ["ca1", "ca2"] + ssl_certificate = "cert" + ssl_key = "key" + ssl_key_passphrase = "pass" + } +} ` tcpMonitorConfig = ` @@ -198,6 +247,24 @@ resource "elasticstack_kibana_synthetics_monitor" "%s" { } ` + icmpMonitorMinConfig = ` + +resource "elasticstack_kibana_synthetics_monitor" "%s" { + name = "TestIcmpMonitorResource - %s" + private_locations = [elasticstack_kibana_synthetics_private_location.%s.label] + alert = { + status = { + enabled = true + } + tls = { + enabled = true + } + } + icmp = { + host = "localhost" + } +} +` icmpMonitorConfig = ` resource "elasticstack_kibana_synthetics_monitor" "%s" { @@ -270,6 +337,24 @@ resource "elasticstack_kibana_synthetics_monitor" "%s" { inline_script = "step('Go to https://google.com.co', () => page.goto('https://www.google.com'))" } } +` + browserMonitorMinConfig = ` + +resource "elasticstack_kibana_synthetics_monitor" "%s" { + name = "TestBrowserMonitorResource - %s" + private_locations = [elasticstack_kibana_synthetics_private_location.%s.label] + alert = { + status = { + enabled = true + } + tls = { + enabled = true + } + } + browser = { + inline_script = "step('Go to https://google.com.co', () => page.goto('https://www.google.com'))" + } +} ` browserMonitorUpdated = ` @@ -308,7 +393,10 @@ func TestSyntheticMonitorHTTPResource(t *testing.T) { httpMonitorId, config := testMonitorConfig(id, httpMonitorConfig, name) bmName := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum) - bmHttpMonitorId, bmConfig := testMonitorConfig("http-monitor-min", httpMonitorMinConfig, bmName) + bmMonitorId, bmConfig := testMonitorConfig("http-monitor-min", httpMonitorMinConfig, bmName) + + sslName := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum) + sslHttpMonitorId, sslConfig := testMonitorConfig("http-monitor-ssl", httpMonitorSslConfig, sslName) _, configUpdated := testMonitorConfig(id, httpMonitorUpdated, name) @@ -321,12 +409,40 @@ func TestSyntheticMonitorHTTPResource(t *testing.T) { SkipFunc: versionutils.CheckIfVersionIsUnsupported(minKibanaVersion), Config: bmConfig, Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttrSet(bmHttpMonitorId, "id"), - resource.TestCheckResourceAttr(bmHttpMonitorId, "name", "TestHttpMonitorResource - "+bmName), - resource.TestCheckResourceAttr(bmHttpMonitorId, "space_id", "default"), - resource.TestCheckResourceAttr(bmHttpMonitorId, "http.url", "http://localhost:5601"), + resource.TestCheckResourceAttrSet(bmMonitorId, "id"), + resource.TestCheckResourceAttr(bmMonitorId, "name", "TestHttpMonitorResource - "+bmName), + resource.TestCheckResourceAttr(bmMonitorId, "space_id", "default"), + resource.TestCheckResourceAttr(bmMonitorId, "http.url", "http://localhost:5601"), + ), + }, + // Create and Read http monitor with ssl fields, starting from ES 8.16.0 + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(kibana816Version), + Config: sslConfig, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet(sslHttpMonitorId, "id"), + resource.TestCheckResourceAttr(sslHttpMonitorId, "name", "TestHttpMonitorResource - "+sslName), + resource.TestCheckResourceAttr(sslHttpMonitorId, "space_id", "default"), + resource.TestCheckResourceAttr(sslHttpMonitorId, "http.url", "http://localhost:5601"), + resource.TestCheckResourceAttr(sslHttpMonitorId, "http.ssl_verification_mode", "full"), + resource.TestCheckResourceAttr(sslHttpMonitorId, "http.ssl_supported_protocols.#", "1"), + resource.TestCheckResourceAttr(sslHttpMonitorId, "http.ssl_supported_protocols.0", "TLSv1.2"), + resource.TestCheckResourceAttr(sslHttpMonitorId, "http.ssl_certificate_authorities.#", "2"), + resource.TestCheckResourceAttr(sslHttpMonitorId, "http.ssl_certificate_authorities.0", "ca1"), + resource.TestCheckResourceAttr(sslHttpMonitorId, "http.ssl_certificate_authorities.1", "ca2"), + resource.TestCheckResourceAttr(sslHttpMonitorId, "http.ssl_certificate", "cert"), + resource.TestCheckResourceAttr(sslHttpMonitorId, "http.ssl_key", "key"), + resource.TestCheckResourceAttr(sslHttpMonitorId, "http.ssl_key_passphrase", "pass"), ), }, + // ImportState testing ssl fields + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(kibana816Version), + ResourceName: sslHttpMonitorId, + ImportState: true, + ImportStateVerify: true, + Config: sslConfig, + }, // Create and Read http monitor { SkipFunc: versionutils.CheckIfVersionIsUnsupported(minKibanaVersion), @@ -423,7 +539,10 @@ func TestSyntheticMonitorTCPResource(t *testing.T) { _, configUpdated := testMonitorConfig(id, tcpMonitorUpdated, name) bmName := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum) - bmTcponitorId, bmConfig := testMonitorConfig("tcp-monitor-min", tcpMonitorMinConfig, bmName) + bmMonitorId, bmConfig := testMonitorConfig("tcp-monitor-min", tcpMonitorMinConfig, bmName) + + sslName := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum) + sslTcpMonitorId, sslConfig := testMonitorConfig("tcp-monitor-ssl", tcpMonitorSslConfig, sslName) resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -434,12 +553,41 @@ func TestSyntheticMonitorTCPResource(t *testing.T) { SkipFunc: versionutils.CheckIfVersionIsUnsupported(minKibanaVersion), Config: bmConfig, Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttrSet(bmTcponitorId, "id"), - resource.TestCheckResourceAttr(bmTcponitorId, "name", "TestTcpMonitorResource - "+bmName), - resource.TestCheckResourceAttr(bmTcponitorId, "space_id", "default"), - resource.TestCheckResourceAttr(bmTcponitorId, "tcp.host", "http://localhost:5601"), + resource.TestCheckResourceAttrSet(bmMonitorId, "id"), + resource.TestCheckResourceAttr(bmMonitorId, "name", "TestTcpMonitorResource - "+bmName), + resource.TestCheckResourceAttr(bmMonitorId, "space_id", "default"), + resource.TestCheckResourceAttr(bmMonitorId, "tcp.host", "http://localhost:5601"), ), }, + // Create and Read tcp monitor with ssl fields, starting from ES 8.16.0 + // Create and Read tcp monitor with ssl fields, starting from ES 8.16.0 + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(kibana816Version), + Config: sslConfig, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet(sslTcpMonitorId, "id"), + resource.TestCheckResourceAttr(sslTcpMonitorId, "name", "TestHttpMonitorResource - "+sslName), + resource.TestCheckResourceAttr(sslTcpMonitorId, "space_id", "default"), + resource.TestCheckResourceAttr(sslTcpMonitorId, "tcp.host", "http://localhost:5601"), + resource.TestCheckResourceAttr(sslTcpMonitorId, "tcp.ssl_verification_mode", "full"), + resource.TestCheckResourceAttr(sslTcpMonitorId, "tcp.ssl_supported_protocols.#", "1"), + resource.TestCheckResourceAttr(sslTcpMonitorId, "tcp.ssl_supported_protocols.0", "TLSv1.2"), + resource.TestCheckResourceAttr(sslTcpMonitorId, "tcp.ssl_certificate_authorities.#", "2"), + resource.TestCheckResourceAttr(sslTcpMonitorId, "tcp.ssl_certificate_authorities.0", "ca1"), + resource.TestCheckResourceAttr(sslTcpMonitorId, "tcp.ssl_certificate_authorities.1", "ca2"), + resource.TestCheckResourceAttr(sslTcpMonitorId, "tcp.ssl_certificate", "cert"), + resource.TestCheckResourceAttr(sslTcpMonitorId, "tcp.ssl_key", "key"), + resource.TestCheckResourceAttr(sslTcpMonitorId, "tcp.ssl_key_passphrase", "pass"), + ), + }, + // ImportState testing ssl fields + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(kibana816Version), + ResourceName: sslTcpMonitorId, + ImportState: true, + ImportStateVerify: true, + Config: sslConfig, + }, // Create and Read tcp monitor { SkipFunc: versionutils.CheckIfVersionIsUnsupported(minKibanaVersion), @@ -525,10 +673,24 @@ func TestSyntheticMonitorICMPResource(t *testing.T) { icmpMonitorId, config := testMonitorConfig(id, icmpMonitorConfig, name) _, configUpdated := testMonitorConfig(id, icmpMonitorUpdated, name) + bmName := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum) + bmMonitorId, bmConfig := testMonitorConfig("icmp-monitor-min", icmpMonitorMinConfig, bmName) + resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.Providers, Steps: []resource.TestStep{ + // Create and Read icmp monitor with minimum fields + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minKibanaVersion), + Config: bmConfig, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet(bmMonitorId, "id"), + resource.TestCheckResourceAttr(bmMonitorId, "name", "TestIcmpMonitorResource - "+bmName), + resource.TestCheckResourceAttr(bmMonitorId, "space_id", "default"), + resource.TestCheckResourceAttr(bmMonitorId, "icmp.host", "localhost"), + ), + }, // Create and Read icmp monitor { @@ -601,11 +763,24 @@ func TestSyntheticMonitorBrowserResource(t *testing.T) { browserMonitorId, config := testMonitorConfig(id, browserMonitorConfig, name) _, configUpdated := testMonitorConfig(id, browserMonitorUpdated, name) + bmName := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum) + bmMonitorId, bmConfig := testMonitorConfig("browser-monitor-min", browserMonitorMinConfig, bmName) + resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.Providers, Steps: []resource.TestStep{ - + // Create and Read browser monitor with minimum fields + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minKibanaVersion), + Config: bmConfig, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet(bmMonitorId, "id"), + resource.TestCheckResourceAttr(bmMonitorId, "name", "TestBrowserMonitorResource - "+bmName), + resource.TestCheckResourceAttr(bmMonitorId, "space_id", "default"), + resource.TestCheckResourceAttr(bmMonitorId, "browser.inline_script", "step('Go to https://google.com.co', () => page.goto('https://www.google.com'))"), + ), + }, // Create and Read browser monitor { SkipFunc: versionutils.CheckIfVersionIsUnsupported(minKibanaVersion), diff --git a/internal/kibana/synthetics/schema_test.go b/internal/kibana/synthetics/schema_test.go index 48a999ef6..087ba538f 100644 --- a/internal/kibana/synthetics/schema_test.go +++ b/internal/kibana/synthetics/schema_test.go @@ -467,11 +467,15 @@ func TestToKibanaAPIRequest(t *testing.T) { ProxyURL: types.StringValue("https://proxy.com"), Response: jsontypes.NewNormalizedValue(`{"response1":"value1"}`), Check: jsontypes.NewNormalizedValue(`{"check1":"value1"}`), - tfSSLConfig: tfSSLConfig{ //TODO: add fields + tfSSLConfig: tfSSLConfig{ SslVerificationMode: types.StringValue("full"), SslSupportedProtocols: types.ListValueMust(types.StringType, []attr.Value{ types.StringValue("TLSv1.2"), types.StringValue("TLSv1.3"), }), + SslCertificateAuthorities: []types.String{types.StringValue("cert1"), types.StringValue("cert2")}, + SslCertificate: types.StringValue("cert"), + SslKey: types.StringValue("key"), + SslKeyPassphrase: types.StringValue("passphrase"), }, }, }, @@ -491,9 +495,13 @@ func TestToKibanaAPIRequest(t *testing.T) { }, fields: kbapi.HTTPMonitorFields{ Url: "https://example.com", - Ssl: &kbapi.SSLConfig{ //TODO - VerificationMode: "full", - SupportedProtocols: []string{"TLSv1.2", "TLSv1.3"}, + Ssl: &kbapi.SSLConfig{ + VerificationMode: "full", + SupportedProtocols: []string{"TLSv1.2", "TLSv1.3"}, + CertificateAuthorities: []string{"cert1", "cert2"}, + Certificate: "cert", + Key: "key", + KeyPassphrase: "passphrase", }, MaxRedirects: "5", Mode: "all", @@ -525,11 +533,15 @@ func TestToKibanaAPIRequest(t *testing.T) { Params: jsontypes.NewNormalizedValue(`{"param1":"value1"}`), TCP: &tfTCPMonitorFieldsV0{ Host: types.StringValue("example.com:9200"), - tfSSLConfig: tfSSLConfig{ //TODO: add fields + tfSSLConfig: tfSSLConfig{ SslVerificationMode: types.StringValue("full"), SslSupportedProtocols: types.ListValueMust(types.StringType, []attr.Value{ types.StringValue("TLSv1.2"), types.StringValue("TLSv1.3"), }), + SslCertificateAuthorities: []types.String{types.StringValue("cert1"), types.StringValue("cert2")}, + SslCertificate: types.StringValue("cert"), + SslKey: types.StringValue("key"), + SslKeyPassphrase: types.StringValue("passphrase"), }, CheckSend: types.StringValue("hello"), CheckReceive: types.StringValue("world"), @@ -554,8 +566,12 @@ func TestToKibanaAPIRequest(t *testing.T) { fields: kbapi.TCPMonitorFields{ Host: "example.com:9200", Ssl: &kbapi.SSLConfig{ - VerificationMode: "full", - SupportedProtocols: []string{"TLSv1.2", "TLSv1.3"}, + VerificationMode: "full", + SupportedProtocols: []string{"TLSv1.2", "TLSv1.3"}, + CertificateAuthorities: []string{"cert1", "cert2"}, + Certificate: "cert", + Key: "key", + KeyPassphrase: "passphrase", }, CheckSend: "hello", CheckReceive: "world", From 16b62167017e3e4b28b6abfd15ecdf6a4f6ba70f Mon Sep 17 00:00:00 2001 From: Boris Ilyushonak Date: Fri, 20 Dec 2024 18:37:15 +0100 Subject: [PATCH 11/13] make alert `UseStateForUnknown` --- CHANGELOG.md | 2 + internal/kibana/synthetics/acc_test.go | 56 ++++------------------ internal/kibana/synthetics/schema.go | 57 ++++++++++++++++------- internal/kibana/synthetics/schema_test.go | 27 +++++++---- 4 files changed, 68 insertions(+), 74 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 129092171..454391f7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ ## [Unreleased] - Support 8.15.5 in acc tests ([#963](https://github.com/elastic/terraform-provider-elasticstack/pull/963)). +- Support 8.16.2 in acc tests ([#964](https://github.com/elastic/terraform-provider-elasticstack/pull/964)). +- Support several ssl fields in `elasticstack_kibana_synthetics_monitor` ([#967](https://github.com/elastic/terraform-provider-elasticstack/pull/967)) ## [0.11.12] - 2024-12-16 diff --git a/internal/kibana/synthetics/acc_test.go b/internal/kibana/synthetics/acc_test.go index 62b074098..dca2ed096 100644 --- a/internal/kibana/synthetics/acc_test.go +++ b/internal/kibana/synthetics/acc_test.go @@ -22,14 +22,6 @@ const ( resource "elasticstack_kibana_synthetics_monitor" "%s" { name = "TestHttpMonitorResource - %s" private_locations = [elasticstack_kibana_synthetics_private_location.%s.label] - alert = { - status = { - enabled = false - } - tls = { - enabled = false - } - } http = { url = "http://localhost:5601" } @@ -67,14 +59,6 @@ resource "elasticstack_kibana_synthetics_monitor" "%s" { resource "elasticstack_kibana_synthetics_monitor" "%s" { name = "TestHttpMonitorResource - %s" private_locations = [elasticstack_kibana_synthetics_private_location.%s.label] - alert = { - status = { - enabled = true - } - tls = { - enabled = true - } - } http = { url = "http://localhost:5601" ssl_verification_mode = "full" @@ -152,14 +136,6 @@ resource "elasticstack_kibana_synthetics_monitor" "%s" { resource "elasticstack_kibana_synthetics_monitor" "%s" { name = "TestTcpMonitorResource - %s" private_locations = [elasticstack_kibana_synthetics_private_location.%s.label] - alert = { - status = { - enabled = true - } - tls = { - enabled = true - } - } tcp = { host = "http://localhost:5601" } @@ -171,14 +147,6 @@ resource "elasticstack_kibana_synthetics_monitor" "%s" { resource "elasticstack_kibana_synthetics_monitor" "%s" { name = "TestHttpMonitorResource - %s" private_locations = [elasticstack_kibana_synthetics_private_location.%s.label] - alert = { - status = { - enabled = true - } - tls = { - enabled = true - } - } tcp = { host = "http://localhost:5601" ssl_verification_mode = "full" @@ -252,14 +220,6 @@ resource "elasticstack_kibana_synthetics_monitor" "%s" { resource "elasticstack_kibana_synthetics_monitor" "%s" { name = "TestIcmpMonitorResource - %s" private_locations = [elasticstack_kibana_synthetics_private_location.%s.label] - alert = { - status = { - enabled = true - } - tls = { - enabled = true - } - } icmp = { host = "localhost" } @@ -323,14 +283,6 @@ resource "elasticstack_kibana_synthetics_monitor" "%s" { private_locations = [elasticstack_kibana_synthetics_private_location.%s.label] enabled = true tags = ["a", "b"] - alert = { - status = { - enabled = true - } - tls = { - enabled = true - } - } service_name = "test apm service" timeout = 30 browser = { @@ -412,6 +364,8 @@ func TestSyntheticMonitorHTTPResource(t *testing.T) { resource.TestCheckResourceAttrSet(bmMonitorId, "id"), resource.TestCheckResourceAttr(bmMonitorId, "name", "TestHttpMonitorResource - "+bmName), resource.TestCheckResourceAttr(bmMonitorId, "space_id", "default"), + resource.TestCheckResourceAttr(bmMonitorId, "alert.status.enabled", "true"), + resource.TestCheckResourceAttr(bmMonitorId, "alert.tls.enabled", "true"), resource.TestCheckResourceAttr(bmMonitorId, "http.url", "http://localhost:5601"), ), }, @@ -557,6 +511,8 @@ func TestSyntheticMonitorTCPResource(t *testing.T) { resource.TestCheckResourceAttr(bmMonitorId, "name", "TestTcpMonitorResource - "+bmName), resource.TestCheckResourceAttr(bmMonitorId, "space_id", "default"), resource.TestCheckResourceAttr(bmMonitorId, "tcp.host", "http://localhost:5601"), + resource.TestCheckResourceAttr(bmMonitorId, "alert.status.enabled", "true"), + resource.TestCheckResourceAttr(bmMonitorId, "alert.tls.enabled", "true"), ), }, // Create and Read tcp monitor with ssl fields, starting from ES 8.16.0 @@ -689,6 +645,8 @@ func TestSyntheticMonitorICMPResource(t *testing.T) { resource.TestCheckResourceAttr(bmMonitorId, "name", "TestIcmpMonitorResource - "+bmName), resource.TestCheckResourceAttr(bmMonitorId, "space_id", "default"), resource.TestCheckResourceAttr(bmMonitorId, "icmp.host", "localhost"), + resource.TestCheckResourceAttr(bmMonitorId, "alert.status.enabled", "true"), + resource.TestCheckResourceAttr(bmMonitorId, "alert.tls.enabled", "true"), ), }, @@ -779,6 +737,8 @@ func TestSyntheticMonitorBrowserResource(t *testing.T) { resource.TestCheckResourceAttr(bmMonitorId, "name", "TestBrowserMonitorResource - "+bmName), resource.TestCheckResourceAttr(bmMonitorId, "space_id", "default"), resource.TestCheckResourceAttr(bmMonitorId, "browser.inline_script", "step('Go to https://google.com.co', () => page.goto('https://www.google.com'))"), + resource.TestCheckResourceAttr(bmMonitorId, "alert.status.enabled", "true"), + resource.TestCheckResourceAttr(bmMonitorId, "alert.tls.enabled", "true"), ), }, // Create and Read browser monitor diff --git a/internal/kibana/synthetics/schema.go b/internal/kibana/synthetics/schema.go index 08dd95137..d1281de8b 100644 --- a/internal/kibana/synthetics/schema.go +++ b/internal/kibana/synthetics/schema.go @@ -11,16 +11,20 @@ import ( "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "strconv" ) @@ -99,7 +103,7 @@ type tfModelV0 struct { PrivateLocations []types.String `tfsdk:"private_locations"` Enabled types.Bool `tfsdk:"enabled"` Tags []types.String `tfsdk:"tags"` - Alert *tfAlertConfigV0 `tfsdk:"alert"` + Alert types.Object `tfsdk:"alert"` //tfAlertConfigV0 APMServiceName types.String `tfsdk:"service_name"` TimeoutSeconds types.Int64 `tfsdk:"timeout"` HTTP *tfHTTPMonitorFieldsV0 `tfsdk:"http"` @@ -302,11 +306,8 @@ func monitorAlertConfigSchema() schema.Attribute { "status": statusConfigSchema(), "tls": statusConfigSchema(), }, - //Computed: true, - // try object type and - //types.ObjectValueFrom() - //tfsdk.ValueAs() - //PlanModifiers: []planmodifier.Object{objectplanmodifier.UseStateForUnknown()}, //TODO: verify if that is correct + Computed: true, + PlanModifiers: []planmodifier.Object{objectplanmodifier.UseStateForUnknown()}, } } @@ -638,6 +639,11 @@ func (v *tfModelV0) toModelV0(ctx context.Context, api *kbapi.SyntheticsMonitor) ResourceId: string(api.Id), } + alertV0, dg := toTfAlertConfigV0(ctx, api.Alert) + if dg.HasError() { + return nil, dg + } + return &tfModelV0{ ID: types.StringValue(resourceID.String()), Name: types.StringValue(api.Name), @@ -647,7 +653,7 @@ func (v *tfModelV0) toModelV0(ctx context.Context, api *kbapi.SyntheticsMonitor) PrivateLocations: StringSliceValue(privateLocLabels), Enabled: types.BoolPointerValue(api.Enabled), Tags: StringSliceValue(api.Tags), - Alert: toTfAlertConfigV0(api.Alert), + Alert: alertV0, APMServiceName: types.StringValue(api.APMServiceName), TimeoutSeconds: types.Int64Value(timeout), Params: params, @@ -787,14 +793,24 @@ func (v *tfHTTPMonitorFieldsV0) toTfHTTPMonitorFieldsV0(ctx context.Context, dg } } -func toTfAlertConfigV0(alert *kbapi.MonitorAlertConfig) *tfAlertConfigV0 { +func toTfAlertConfigV0(ctx context.Context, alert *kbapi.MonitorAlertConfig) (basetypes.ObjectValue, diag.Diagnostics) { + + dg := diag.Diagnostics{} + + alertAttributes := monitorAlertConfigSchema().GetType().(attr.TypeWithAttributeTypes).AttributeTypes() + + var emptyAttr = map[string]attr.Type(nil) + if alert == nil { - return nil + return basetypes.NewObjectNull(emptyAttr), dg } - return &tfAlertConfigV0{ + + tfAlertConfig := tfAlertConfigV0{ Status: toTfStatusConfigV0(alert.Status), TLS: toTfStatusConfigV0(alert.Tls), } + + return types.ObjectValueFrom(ctx, alertAttributes, &tfAlertConfig) } func toTfStatusConfigV0(status *kbapi.SyntheticsStatusConfig) *tfStatusConfigV0 { @@ -812,7 +828,7 @@ func (v *tfModelV0) toKibanaAPIRequest(ctx context.Context) (*kibanaAPIRequest, if dg.HasError() { return nil, dg } - config, dg := v.toSyntheticsMonitorConfig() + config, dg := v.toSyntheticsMonitorConfig(ctx) if dg.HasError() { return nil, dg } @@ -839,18 +855,23 @@ func (v *tfModelV0) toMonitorFields(ctx context.Context) (kbapi.MonitorFields, d return nil, dg } -func (v *tfModelV0) toSyntheticsMonitorConfig() (*kbapi.SyntheticsMonitorConfig, diag.Diagnostics) { +func toTFAlertConfit(ctx context.Context, v basetypes.ObjectValue) *kbapi.MonitorAlertConfig { + var alert *kbapi.MonitorAlertConfig + if !(v.IsNull() || v.IsUnknown()) { + tfAlert := tfAlertConfigV0{} + tfsdk.ValueAs(ctx, v, &tfAlert) + alert = tfAlert.toTfAlertConfigV0() + } + return alert +} + +func (v *tfModelV0) toSyntheticsMonitorConfig(ctx context.Context) (*kbapi.SyntheticsMonitorConfig, diag.Diagnostics) { locations := Map[types.String, kbapi.MonitorLocation](v.Locations, func(s types.String) kbapi.MonitorLocation { return kbapi.MonitorLocation(s.ValueString()) }) params, dg := toJsonObject(v.Params) if dg.HasError() { return nil, dg } - var alert *kbapi.MonitorAlertConfig - if v.Alert != nil { - alert = v.Alert.toTfAlertConfigV0() - } - return &kbapi.SyntheticsMonitorConfig{ Name: v.Name.ValueString(), Schedule: kbapi.MonitorSchedule(v.Schedule.ValueInt64()), @@ -858,7 +879,7 @@ func (v *tfModelV0) toSyntheticsMonitorConfig() (*kbapi.SyntheticsMonitorConfig, PrivateLocations: ValueStringSlice(v.PrivateLocations), Enabled: v.Enabled.ValueBoolPointer(), Tags: ValueStringSlice(v.Tags), - Alert: alert, + Alert: toTFAlertConfit(ctx, v.Alert), APMServiceName: v.APMServiceName.ValueString(), TimeoutSeconds: int(v.TimeoutSeconds.ValueInt64()), Namespace: v.SpaceID.ValueString(), diff --git a/internal/kibana/synthetics/schema_test.go b/internal/kibana/synthetics/schema_test.go index 087ba538f..1711530bf 100644 --- a/internal/kibana/synthetics/schema_test.go +++ b/internal/kibana/synthetics/schema_test.go @@ -3,6 +3,7 @@ package synthetics import ( "context" "encoding/json" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "testing" "github.com/disaster37/go-kibana-rest/v8/kbapi" @@ -23,6 +24,16 @@ func boolPointer(v bool) *bool { return res } +func toAlertObject(t *testing.T, v tfAlertConfigV0) basetypes.ObjectValue { + + alertAttributes := monitorAlertConfigSchema().GetType().(attr.TypeWithAttributeTypes).AttributeTypes() + from, dg := types.ObjectValueFrom(context.Background(), alertAttributes, &v) + if dg.HasError() { + t.Fatalf("Failed to create Alert object: %v", dg) + } + return from +} + func TestToModelV0(t *testing.T) { testcases := []struct { name string @@ -185,7 +196,7 @@ func TestToModelV0(t *testing.T) { PrivateLocations: []types.String{types.StringValue("test private location")}, Enabled: types.BoolPointerValue(tBool), Tags: []types.String{types.StringValue("tag1"), types.StringValue("tag2")}, - Alert: &tfAlertConfigV0{Status: &tfStatusConfigV0{Enabled: types.BoolPointerValue(tBool)}, TLS: &tfStatusConfigV0{Enabled: types.BoolPointerValue(fBool)}}, + Alert: toAlertObject(t, tfAlertConfigV0{Status: &tfStatusConfigV0{Enabled: types.BoolPointerValue(tBool)}, TLS: &tfStatusConfigV0{Enabled: types.BoolPointerValue(fBool)}}), APMServiceName: types.StringValue("test-service-http"), TimeoutSeconds: types.Int64Value(30), Params: jsontypes.NewNormalizedValue(`{"param1":"value1"}`), @@ -255,7 +266,7 @@ func TestToModelV0(t *testing.T) { PrivateLocations: []types.String{types.StringValue("test private location")}, Enabled: types.BoolPointerValue(tBool), Tags: nil, - Alert: &tfAlertConfigV0{Status: &tfStatusConfigV0{Enabled: types.BoolPointerValue(tBool)}}, + Alert: toAlertObject(t, tfAlertConfigV0{Status: &tfStatusConfigV0{Enabled: types.BoolPointerValue(tBool)}}), APMServiceName: types.StringValue("test-service-tcp"), TimeoutSeconds: types.Int64Value(30), Params: jsontypes.NewNormalizedValue(`{"param1":"value1"}`), @@ -314,7 +325,7 @@ func TestToModelV0(t *testing.T) { PrivateLocations: []types.String{types.StringValue("test private location")}, Enabled: types.BoolPointerValue(tBool), Tags: nil, - Alert: &tfAlertConfigV0{Status: &tfStatusConfigV0{Enabled: types.BoolPointerValue(tBool)}}, + Alert: toAlertObject(t, tfAlertConfigV0{Status: &tfStatusConfigV0{Enabled: types.BoolPointerValue(tBool)}}), APMServiceName: types.StringValue("test-service-tcp"), TimeoutSeconds: types.Int64Value(30), Params: jsontypes.NewNormalizedValue(`{"param1":"value1"}`), @@ -369,7 +380,7 @@ func TestToModelV0(t *testing.T) { PrivateLocations: []types.String{types.StringValue("test private location")}, Enabled: types.BoolPointerValue(tBool), Tags: nil, - Alert: &tfAlertConfigV0{Status: &tfStatusConfigV0{Enabled: types.BoolPointerValue(tBool)}}, + Alert: toAlertObject(t, tfAlertConfigV0{Status: &tfStatusConfigV0{Enabled: types.BoolPointerValue(tBool)}}), APMServiceName: types.StringValue("test-service-tcp"), TimeoutSeconds: types.Int64Value(30), Params: jsontypes.NewNormalizedValue(`{"param1":"value1"}`), @@ -451,7 +462,7 @@ func TestToKibanaAPIRequest(t *testing.T) { PrivateLocations: []types.String{types.StringValue("test private location")}, Enabled: types.BoolPointerValue(tBool), Tags: []types.String{types.StringValue("tag1"), types.StringValue("tag2")}, - Alert: &tfAlertConfigV0{Status: &tfStatusConfigV0{Enabled: types.BoolPointerValue(tBool)}, TLS: &tfStatusConfigV0{Enabled: types.BoolPointerValue(fBool)}}, + Alert: toAlertObject(t, tfAlertConfigV0{Status: &tfStatusConfigV0{Enabled: types.BoolPointerValue(tBool)}, TLS: &tfStatusConfigV0{Enabled: types.BoolPointerValue(fBool)}}), APMServiceName: types.StringValue("test-service-http"), TimeoutSeconds: types.Int64Value(30), Params: jsontypes.NewNormalizedValue(`{"param1":"value1"}`), @@ -527,7 +538,7 @@ func TestToKibanaAPIRequest(t *testing.T) { PrivateLocations: nil, Enabled: types.BoolPointerValue(tBool), Tags: []types.String{types.StringValue("tag1"), types.StringValue("tag2")}, - Alert: &tfAlertConfigV0{Status: &tfStatusConfigV0{Enabled: types.BoolPointerValue(tBool)}}, + Alert: toAlertObject(t, tfAlertConfigV0{Status: &tfStatusConfigV0{Enabled: types.BoolPointerValue(tBool)}}), APMServiceName: types.StringValue("test-service-tcp"), TimeoutSeconds: types.Int64Value(30), Params: jsontypes.NewNormalizedValue(`{"param1":"value1"}`), @@ -591,7 +602,7 @@ func TestToKibanaAPIRequest(t *testing.T) { PrivateLocations: nil, Enabled: types.BoolPointerValue(tBool), Tags: []types.String{types.StringValue("tag1"), types.StringValue("tag2")}, - Alert: &tfAlertConfigV0{Status: &tfStatusConfigV0{Enabled: types.BoolPointerValue(tBool)}}, + Alert: toAlertObject(t, tfAlertConfigV0{Status: &tfStatusConfigV0{Enabled: types.BoolPointerValue(tBool)}}), APMServiceName: types.StringValue("test-service-tcp"), TimeoutSeconds: types.Int64Value(30), Params: jsontypes.NewNormalizedValue(`{"param1":"value1"}`), @@ -631,7 +642,7 @@ func TestToKibanaAPIRequest(t *testing.T) { PrivateLocations: nil, Enabled: types.BoolPointerValue(tBool), Tags: []types.String{types.StringValue("tag1"), types.StringValue("tag2")}, - Alert: &tfAlertConfigV0{Status: &tfStatusConfigV0{Enabled: types.BoolPointerValue(tBool)}}, + Alert: toAlertObject(t, tfAlertConfigV0{Status: &tfStatusConfigV0{Enabled: types.BoolPointerValue(tBool)}}), APMServiceName: types.StringValue("test-service-tcp"), TimeoutSeconds: types.Int64Value(30), Params: jsontypes.NewNormalizedValue(`{"param1":"value1"}`), From f6e2767289b4444d9fa9558887eda5dc272bfe81 Mon Sep 17 00:00:00 2001 From: Boris Ilyushonak Date: Fri, 20 Dec 2024 18:42:29 +0100 Subject: [PATCH 12/13] dry --- internal/kibana/synthetics/schema.go | 38 +++++++++++++--------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/internal/kibana/synthetics/schema.go b/internal/kibana/synthetics/schema.go index d1281de8b..5ea20a42c 100644 --- a/internal/kibana/synthetics/schema.go +++ b/internal/kibana/synthetics/schema.go @@ -674,7 +674,8 @@ func (v *tfTCPMonitorFieldsV0) toTfTCPMonitorFieldsV0(ctx context.Context, dg di if api.CheckReceive != "" { checkReceive = types.StringValue(api.CheckReceive) } - sslSupportedProtocols := utils.SliceToListType_String(ctx, api.SslSupportedProtocols, path.Root("tcp").AtName("ssl_supported_protocols"), &dg) + sslCfg, dg := toTFSSLConfig(ctx, dg, api, "tcp") + if dg.HasError() { return nil } @@ -684,14 +685,7 @@ func (v *tfTCPMonitorFieldsV0) toTfTCPMonitorFieldsV0(ctx context.Context, dg di CheckReceive: checkReceive, ProxyURL: types.StringValue(api.ProxyUrl), ProxyUseLocalResolver: types.BoolPointerValue(api.ProxyUseLocalResolver), - tfSSLConfig: tfSSLConfig{ - SslVerificationMode: types.StringValue(api.SslVerificationMode), - SslSupportedProtocols: sslSupportedProtocols, - SslCertificateAuthorities: StringSliceValue(api.SslCertificateAuthorities), - SslCertificate: types.StringValue(api.SslCertificate), - SslKey: types.StringValue(api.SslKey), - SslKeyPassphrase: types.StringValue(api.SslKeyPassphrase), - }, + tfSSLConfig: sslCfg, } } @@ -763,9 +757,7 @@ func (v *tfHTTPMonitorFieldsV0) toTfHTTPMonitorFieldsV0(ctx context.Context, dg return nil } - //TODO: DRY with TCP - sslSupportedProtocols := utils.SliceToListType_String(ctx, api.SslSupportedProtocols, path.Root("http").AtName("ssl_supported_protocols"), &dg) - + sslCfg, dg := toTFSSLConfig(ctx, dg, api, "http") if dg.HasError() { return nil } @@ -781,18 +773,22 @@ func (v *tfHTTPMonitorFieldsV0) toTfHTTPMonitorFieldsV0(ctx context.Context, dg ProxyURL: types.StringValue(api.ProxyUrl), Check: v.Check, Response: v.Response, - - tfSSLConfig: tfSSLConfig{ - SslVerificationMode: types.StringValue(api.SslVerificationMode), - SslSupportedProtocols: sslSupportedProtocols, - SslCertificateAuthorities: StringSliceValue(api.SslCertificateAuthorities), - SslCertificate: types.StringValue(api.SslCertificate), - SslKey: types.StringValue(api.SslKey), - SslKeyPassphrase: types.StringValue(api.SslKeyPassphrase), - }, + tfSSLConfig: sslCfg, } } +func toTFSSLConfig(ctx context.Context, dg diag.Diagnostics, api *kbapi.SyntheticsMonitor, p string) (tfSSLConfig, diag.Diagnostics) { + sslSupportedProtocols := utils.SliceToListType_String(ctx, api.SslSupportedProtocols, path.Root(p).AtName("ssl_supported_protocols"), &dg) + return tfSSLConfig{ + SslVerificationMode: types.StringValue(api.SslVerificationMode), + SslSupportedProtocols: sslSupportedProtocols, + SslCertificateAuthorities: StringSliceValue(api.SslCertificateAuthorities), + SslCertificate: types.StringValue(api.SslCertificate), + SslKey: types.StringValue(api.SslKey), + SslKeyPassphrase: types.StringValue(api.SslKeyPassphrase), + }, dg +} + func toTfAlertConfigV0(ctx context.Context, alert *kbapi.MonitorAlertConfig) (basetypes.ObjectValue, diag.Diagnostics) { dg := diag.Diagnostics{} From 11af7fd5307ed70161792ceaf95e26ce6bcb700e Mon Sep 17 00:00:00 2001 From: Boris Ilyushonak Date: Fri, 20 Dec 2024 18:44:05 +0100 Subject: [PATCH 13/13] clean-up --- libs/go-kibana-rest/kbapi/api.kibana_synthetics_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/go-kibana-rest/kbapi/api.kibana_synthetics_test.go b/libs/go-kibana-rest/kbapi/api.kibana_synthetics_test.go index 4cebddacb..ac6d6fbc5 100644 --- a/libs/go-kibana-rest/kbapi/api.kibana_synthetics_test.go +++ b/libs/go-kibana-rest/kbapi/api.kibana_synthetics_test.go @@ -310,7 +310,7 @@ func (s *KBAPITestSuite) TestKibanaSyntheticsMonitorAPI() { Name: fmt.Sprintf("test synthetics browser monitor %s", testUuid), PrivateLocations: []string{location.Label}, }, - fields: BrowserMonitorFields{ //TODO: check that get returns it - inline_script + fields: BrowserMonitorFields{ InlineScript: `step('Go to https://google.com.co', () => page.goto('https://www.google.com'))`, }, },