From 9dcaca2ed9fbabe84c74ce833daa544398bae085 Mon Sep 17 00:00:00 2001 From: Toby Brain Date: Mon, 6 Nov 2023 23:34:57 +1100 Subject: [PATCH 01/12] Fix acceptance tests (#472) * Fixup error regex for 8.10+ * Don't enforce a value for custom indicator results --- internal/kibana/slo_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/kibana/slo_test.go b/internal/kibana/slo_test.go index fb60506c7..ce2187fa3 100644 --- a/internal/kibana/slo_test.go +++ b/internal/kibana/slo_test.go @@ -95,8 +95,8 @@ func TestAccResourceSlo(t *testing.T) { resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.good.0.field", "test"), resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.good.0.aggregation", "value_count"), resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.good.0.filter", "latency < 300"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.good.0.from", "0"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.good.0.to", "10"), + resource.TestCheckResourceAttrSet("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.good.0.from"), + resource.TestCheckResourceAttrSet("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.good.0.to"), resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.total.0.field", "test"), resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.total.0.aggregation", "value_count"), ), @@ -189,7 +189,7 @@ func TestAccResourceSloErrors(t *testing.T) { { SkipFunc: versionutils.CheckIfVersionIsUnsupported(version.Must(version.NewSemver("8.10.0-SNAPSHOT"))), Config: getSLOConfig("failwhale", "histogram_custom_indicator_agg_fail", false), - ExpectError: regexp.MustCompile(`expected histogram_custom_indicator.0.good.0.aggregation to be one of \[value_count range\], got supdawg`), + ExpectError: regexp.MustCompile(`expected histogram_custom_indicator.0.good.0.aggregation to be one of \["?value_count"? "?range"?\], got supdawg`), }, { SkipFunc: versionutils.CheckIfVersionIsUnsupported(version.Must(version.NewSemver("8.9.0"))), From 499eead8d4d08dedf55f17576e473a9696a76761 Mon Sep 17 00:00:00 2001 From: Taylor Swanson <90622908+taylor-swanson@users.noreply.github.com> Date: Tue, 14 Nov 2023 21:47:22 -0600 Subject: [PATCH 02/12] Rename fleet package objects to use integration terminology (#476) * Rename fleet package objects to use integration terminology - Renamed fleet_package resource/data source to fleet_integration - Renamed fleet_package_policy resource to fleet_integration_policy * Changelog --- CHANGELOG.md | 3 + ...{fleet_package.md => fleet_integration.md} | 10 +- ...{fleet_package.md => fleet_integration.md} | 12 +- ..._policy.md => fleet_integration_policy.md} | 48 ++--- .../data-source.tf | 2 +- .../resource.tf | 2 +- .../import.sh | 1 + .../resource.tf | 22 +- .../import.sh | 1 - ...a_source.go => integration_data_source.go} | 10 +- ...est.go => integration_data_source_test.go} | 16 +- ...urce.go => integration_policy_resource.go} | 56 ++--- .../fleet/integration_policy_resource_test.go | 204 ++++++++++++++++++ ...ge_resource.go => integration_resource.go} | 28 +-- ...e_test.go => integration_resource_test.go} | 16 +- .../fleet/package_policy_resource_test.go | 204 ------------------ provider/provider.go | 12 +- ...kage.md.tmpl => fleet_integration.md.tmpl} | 6 +- ...kage.md.tmpl => fleet_integration.md.tmpl} | 6 +- ....tmpl => fleet_integration_policy.md.tmpl} | 12 +- 20 files changed, 337 insertions(+), 334 deletions(-) rename docs/data-sources/{fleet_package.md => fleet_integration.md} (78%) rename docs/resources/{fleet_package.md => fleet_integration.md} (64%) rename docs/resources/{fleet_package_policy.md => fleet_integration_policy.md} (63%) rename examples/data-sources/{elasticstack_fleet_package => elasticstack_fleet_integration}/data-source.tf (55%) rename examples/resources/{elasticstack_fleet_package => elasticstack_fleet_integration}/resource.tf (61%) create mode 100644 examples/resources/elasticstack_fleet_integration_policy/import.sh rename examples/resources/{elasticstack_fleet_package_policy => elasticstack_fleet_integration_policy}/resource.tf (66%) delete mode 100644 examples/resources/elasticstack_fleet_package_policy/import.sh rename internal/fleet/{package_data_source.go => integration_data_source.go} (81%) rename internal/fleet/{package_data_source_test.go => integration_data_source_test.go} (75%) rename internal/fleet/{package_policy_resource.go => integration_policy_resource.go} (82%) create mode 100644 internal/fleet/integration_policy_resource_test.go rename internal/fleet/{package_resource.go => integration_resource.go} (66%) rename internal/fleet/{package_resource_test.go => integration_resource_test.go} (61%) delete mode 100644 internal/fleet/package_policy_resource_test.go rename templates/data-sources/{fleet_package.md.tmpl => fleet_integration.md.tmpl} (79%) rename templates/resources/{fleet_package.md.tmpl => fleet_integration.md.tmpl} (74%) rename templates/resources/{fleet_package_policy.md.tmpl => fleet_integration_policy.md.tmpl} (64%) diff --git a/CHANGELOG.md b/CHANGELOG.md index eeccc7548..03f984f2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ - Switch to Terraform [protocol version 6](https://developer.hashicorp.com/terraform/plugin/terraform-plugin-protocol#protocol-version-6) that is compatible with Terraform CLI version 1.0 and later. - Add 'elasticstack_fleet_package' data source ([#469](https://github.com/elastic/terraform-provider-elasticstack/pull/469)) +### Fixed +- Rename fleet package objects to `elasticstack_fleet_integration` and `elasticstack_fleet_integration_policy` ([#476](https://github.com/elastic/terraform-provider-elasticstack/pull/476)) + ## [0.10.0] - 2023-11-02 ### Added diff --git a/docs/data-sources/fleet_package.md b/docs/data-sources/fleet_integration.md similarity index 78% rename from docs/data-sources/fleet_package.md rename to docs/data-sources/fleet_integration.md index d345c94c2..4b329781c 100644 --- a/docs/data-sources/fleet_package.md +++ b/docs/data-sources/fleet_integration.md @@ -1,12 +1,12 @@ --- subcategory: "Fleet" layout: "" -page_title: "Elasticstack: elasticstack_fleet_package Data Source" +page_title: "Elasticstack: elasticstack_fleet_integration Data Source" description: |- Gets information about a Fleet integration package. --- -# Data Source: elasticstack_fleet_package +# Data Source: elasticstack_fleet_integration This data source provides information about a Fleet integration package. Currently, the data source will retrieve the latest available version of the package. Version @@ -26,7 +26,7 @@ provider "elasticstack" { kibana {} } -data "elasticstack_fleet_package" "test" { +data "elasticstack_fleet_integration" "test" { name = "tcp" } ``` @@ -36,7 +36,7 @@ data "elasticstack_fleet_package" "test" { ### Required -- `name` (String) The package name. +- `name` (String) The integration package name. ### Optional @@ -45,4 +45,4 @@ data "elasticstack_fleet_package" "test" { ### Read-Only - `id` (String) The ID of this resource. -- `version` (String) The package version. +- `version` (String) The integration package version. diff --git a/docs/resources/fleet_package.md b/docs/resources/fleet_integration.md similarity index 64% rename from docs/resources/fleet_package.md rename to docs/resources/fleet_integration.md index 2166579e5..d24cd1f11 100644 --- a/docs/resources/fleet_package.md +++ b/docs/resources/fleet_integration.md @@ -1,12 +1,12 @@ --- subcategory: "Fleet" layout: "" -page_title: "Elasticstack: elasticstack_fleet_package Resource" +page_title: "Elasticstack: elasticstack_fleet_integration Resource" description: |- Installs or uninstalls a Fleet integration package. --- -# Resource: elasticstack_fleet_package +# Resource: elasticstack_fleet_integration Installs or uninstalls a Fleet integration package. The Kibana Fleet UI can be used to view available packages. Additional information for managing integration @@ -22,7 +22,7 @@ provider "elasticstack" { kibana {} } -resource "elasticstack_fleet_package" "test_package" { +resource "elasticstack_fleet_integration" "test_integration" { name = "tcp" version = "1.16.0" force = true @@ -34,13 +34,13 @@ resource "elasticstack_fleet_package" "test_package" { ### Required -- `name` (String) The package name. -- `version` (String) The package version. +- `name` (String) The integration package name. +- `version` (String) The integration package version. ### Optional - `force` (Boolean) Set to true to force the requested action. -- `skip_destroy` (Boolean) Set to true if you do not wish the package to be uninstalled at destroy time, and instead just remove the package from the Terraform state. +- `skip_destroy` (Boolean) Set to true if you do not wish the integration package to be uninstalled at destroy time, and instead just remove the integration package from the Terraform state. ### Read-Only diff --git a/docs/resources/fleet_package_policy.md b/docs/resources/fleet_integration_policy.md similarity index 63% rename from docs/resources/fleet_package_policy.md rename to docs/resources/fleet_integration_policy.md index eb5168aa8..a778bc94a 100644 --- a/docs/resources/fleet_package_policy.md +++ b/docs/resources/fleet_integration_policy.md @@ -1,14 +1,14 @@ --- subcategory: "Fleet" layout: "" -page_title: "Elasticstack: elasticstack_fleet_package_policy Resource" +page_title: "Elasticstack: elasticstack_fleet_integration_policy Resource" description: |- - Creates or updates a Fleet Package Policy. + Creates or updates a Fleet Integration Policy. --- -# Resource: elasticstack_fleet_package_policy +# Resource: elasticstack_fleet_integration_policy -Creates or updates a Fleet Package Policy. +Creates or updates a Fleet Integration Policy. It is highly recommended that all inputs and streams are provided in the Terraform plan, even if some are disabled. Otherwise, differences may appear @@ -26,14 +26,14 @@ provider "elasticstack" { fleet {} } -// The package to use. -resource "elasticstack_fleet_package" "sample" { +// The integration to use. +resource "elasticstack_fleet_integration" "sample" { name = "tcp" version = "1.16.0" force = true } -// An agent policy to hold the package policy. +// An agent policy to hold the integration policy. resource "elasticstack_fleet_agent_policy" "sample" { name = "Sample Agent Policy" namespace = "default" @@ -48,14 +48,14 @@ data "elasticstack_fleet_enrollment_tokens" "sample" { policy_id = elasticstack_fleet_agent_policy.sample.policy_id } -// The package policy. -resource "elasticstack_fleet_package_policy" "sample" { - name = "Sample Package Policy" - namespace = "default" - description = "A sample package policy" - agent_policy_id = elasticstack_fleet_agent_policy.sample.policy_id - package_name = elasticstack_fleet_package.sample.name - package_version = elasticstack_fleet_package.sample.version +// The integration policy. +resource "elasticstack_fleet_integration_policy" "sample" { + name = "Sample Integration Policy" + namespace = "default" + description = "A sample integration policy" + agent_policy_id = elasticstack_fleet_agent_policy.sample.policy_id + integration_name = elasticstack_fleet_integration.sample.name + integration_version = elasticstack_fleet_integration.sample.version input { input_id = "tcp-tcp" @@ -84,18 +84,18 @@ resource "elasticstack_fleet_package_policy" "sample" { - `agent_policy_id` (String) ID of the agent policy. - `input` (Block List, Min: 1) (see [below for nested schema](#nestedblock--input)) -- `name` (String) The name of the package policy. -- `namespace` (String) The namespace of the package policy. -- `package_name` (String) The name of the package. -- `package_version` (String) The version of the package. +- `integration_name` (String) The name of the integration package. +- `integration_version` (String) The version of the integration package. +- `name` (String) The name of the integration policy. +- `namespace` (String) The namespace of the integration policy. ### Optional -- `description` (String) The description of the package policy. -- `enabled` (Boolean) Enable the package policy. +- `description` (String) The description of the integration policy. +- `enabled` (Boolean) Enable the integration policy. - `force` (Boolean) Force operations, such as creation and deletion, to occur. -- `policy_id` (String) Unique identifier of the package policy. -- `vars_json` (String, Sensitive) Package-level variables as JSON. +- `policy_id` (String) Unique identifier of the integration policy. +- `vars_json` (String, Sensitive) Integration-level variables as JSON. ### Read-Only @@ -119,5 +119,5 @@ Optional: Import is supported using the following syntax: ```shell -terraform import elasticstack_fleet_package_policy.my_policy +terraform import elasticstack_fleet_integration_policy.my_policy ``` diff --git a/examples/data-sources/elasticstack_fleet_package/data-source.tf b/examples/data-sources/elasticstack_fleet_integration/data-source.tf similarity index 55% rename from examples/data-sources/elasticstack_fleet_package/data-source.tf rename to examples/data-sources/elasticstack_fleet_integration/data-source.tf index bd28fca23..e3626c19d 100644 --- a/examples/data-sources/elasticstack_fleet_package/data-source.tf +++ b/examples/data-sources/elasticstack_fleet_integration/data-source.tf @@ -2,6 +2,6 @@ provider "elasticstack" { kibana {} } -data "elasticstack_fleet_package" "test" { +data "elasticstack_fleet_integration" "test" { name = "tcp" } diff --git a/examples/resources/elasticstack_fleet_package/resource.tf b/examples/resources/elasticstack_fleet_integration/resource.tf similarity index 61% rename from examples/resources/elasticstack_fleet_package/resource.tf rename to examples/resources/elasticstack_fleet_integration/resource.tf index c9d4bf07d..4b2edc72c 100644 --- a/examples/resources/elasticstack_fleet_package/resource.tf +++ b/examples/resources/elasticstack_fleet_integration/resource.tf @@ -2,7 +2,7 @@ provider "elasticstack" { kibana {} } -resource "elasticstack_fleet_package" "test_package" { +resource "elasticstack_fleet_integration" "test_integration" { name = "tcp" version = "1.16.0" force = true diff --git a/examples/resources/elasticstack_fleet_integration_policy/import.sh b/examples/resources/elasticstack_fleet_integration_policy/import.sh new file mode 100644 index 000000000..f5be85cf7 --- /dev/null +++ b/examples/resources/elasticstack_fleet_integration_policy/import.sh @@ -0,0 +1 @@ +terraform import elasticstack_fleet_integration_policy.my_policy diff --git a/examples/resources/elasticstack_fleet_package_policy/resource.tf b/examples/resources/elasticstack_fleet_integration_policy/resource.tf similarity index 66% rename from examples/resources/elasticstack_fleet_package_policy/resource.tf rename to examples/resources/elasticstack_fleet_integration_policy/resource.tf index 616aca71e..58b980086 100644 --- a/examples/resources/elasticstack_fleet_package_policy/resource.tf +++ b/examples/resources/elasticstack_fleet_integration_policy/resource.tf @@ -2,14 +2,14 @@ provider "elasticstack" { fleet {} } -// The package to use. -resource "elasticstack_fleet_package" "sample" { +// The integration to use. +resource "elasticstack_fleet_integration" "sample" { name = "tcp" version = "1.16.0" force = true } -// An agent policy to hold the package policy. +// An agent policy to hold the integration policy. resource "elasticstack_fleet_agent_policy" "sample" { name = "Sample Agent Policy" namespace = "default" @@ -24,14 +24,14 @@ data "elasticstack_fleet_enrollment_tokens" "sample" { policy_id = elasticstack_fleet_agent_policy.sample.policy_id } -// The package policy. -resource "elasticstack_fleet_package_policy" "sample" { - name = "Sample Package Policy" - namespace = "default" - description = "A sample package policy" - agent_policy_id = elasticstack_fleet_agent_policy.sample.policy_id - package_name = elasticstack_fleet_package.sample.name - package_version = elasticstack_fleet_package.sample.version +// The integration policy. +resource "elasticstack_fleet_integration_policy" "sample" { + name = "Sample Integration Policy" + namespace = "default" + description = "A sample integration policy" + agent_policy_id = elasticstack_fleet_agent_policy.sample.policy_id + integration_name = elasticstack_fleet_integration.sample.name + integration_version = elasticstack_fleet_integration.sample.version input { input_id = "tcp-tcp" diff --git a/examples/resources/elasticstack_fleet_package_policy/import.sh b/examples/resources/elasticstack_fleet_package_policy/import.sh deleted file mode 100644 index 85885893b..000000000 --- a/examples/resources/elasticstack_fleet_package_policy/import.sh +++ /dev/null @@ -1 +0,0 @@ -terraform import elasticstack_fleet_package_policy.my_policy diff --git a/internal/fleet/package_data_source.go b/internal/fleet/integration_data_source.go similarity index 81% rename from internal/fleet/package_data_source.go rename to internal/fleet/integration_data_source.go index 3e939b89a..0844df024 100644 --- a/internal/fleet/package_data_source.go +++ b/internal/fleet/integration_data_source.go @@ -10,10 +10,10 @@ import ( "github.com/elastic/terraform-provider-elasticstack/internal/utils" ) -func DataSourcePackage() *schema.Resource { +func DataSourceIntegration() *schema.Resource { packageSchema := map[string]*schema.Schema{ "name": { - Description: "The package name.", + Description: "The integration package name.", Type: schema.TypeString, Required: true, }, @@ -23,7 +23,7 @@ func DataSourcePackage() *schema.Resource { Optional: true, }, "version": { - Description: "The package version.", + Description: "The integration package version.", Type: schema.TypeString, Computed: true, }, @@ -32,13 +32,13 @@ func DataSourcePackage() *schema.Resource { return &schema.Resource{ Description: "Retrieves the latest version of an integration package in Fleet.", - ReadContext: dataSourcePackageRead, + ReadContext: dataSourceIntegrationRead, Schema: packageSchema, } } -func dataSourcePackageRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func dataSourceIntegrationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { fleetClient, diags := getFleetClient(d, meta) if diags.HasError() { return diags diff --git a/internal/fleet/package_data_source_test.go b/internal/fleet/integration_data_source_test.go similarity index 75% rename from internal/fleet/package_data_source_test.go rename to internal/fleet/integration_data_source_test.go index 20d43d569..f059cd627 100644 --- a/internal/fleet/package_data_source_test.go +++ b/internal/fleet/integration_data_source_test.go @@ -12,32 +12,32 @@ import ( "github.com/elastic/terraform-provider-elasticstack/internal/versionutils" ) -var minVersionPackageDataSource = version.Must(version.NewVersion("8.6.0")) +var minVersionIntegrationDataSource = version.Must(version.NewVersion("8.6.0")) -func TestAccDataSourcePackage(t *testing.T) { +func TestAccDataSourceIntegration(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.Providers, Steps: []resource.TestStep{ { - SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionPackageDataSource), - Config: testAccDataSourcePackage, + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionIntegrationDataSource), + Config: testAccDataSourceIntegration, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.elasticstack_fleet_package.test", "name", "tcp"), - checkResourceAttrStringNotEmpty("data.elasticstack_fleet_package.test", "version"), + resource.TestCheckResourceAttr("data.elasticstack_fleet_integration.test", "name", "tcp"), + checkResourceAttrStringNotEmpty("data.elasticstack_fleet_integration.test", "version"), ), }, }, }) } -const testAccDataSourcePackage = ` +const testAccDataSourceIntegration = ` provider "elasticstack" { elasticsearch {} kibana {} } -data "elasticstack_fleet_package" "test" { +data "elasticstack_fleet_integration" "test" { name = "tcp" } ` diff --git a/internal/fleet/package_policy_resource.go b/internal/fleet/integration_policy_resource.go similarity index 82% rename from internal/fleet/package_policy_resource.go rename to internal/fleet/integration_policy_resource.go index 3206e02e3..bc1b77ab7 100644 --- a/internal/fleet/package_policy_resource.go +++ b/internal/fleet/integration_policy_resource.go @@ -12,22 +12,22 @@ import ( "github.com/elastic/terraform-provider-elasticstack/internal/clients/fleet" ) -func ResourcePackagePolicy() *schema.Resource { +func ResourceIntegrationPolicy() *schema.Resource { packagePolicySchema := map[string]*schema.Schema{ "policy_id": { - Description: "Unique identifier of the package policy.", + Description: "Unique identifier of the integration policy.", Type: schema.TypeString, Computed: true, Optional: true, ForceNew: true, }, "name": { - Description: "The name of the package policy.", + Description: "The name of the integration policy.", Type: schema.TypeString, Required: true, }, "namespace": { - Description: "The namespace of the package policy.", + Description: "The namespace of the integration policy.", Type: schema.TypeString, Required: true, }, @@ -37,12 +37,12 @@ func ResourcePackagePolicy() *schema.Resource { Required: true, }, "description": { - Description: "The description of the package policy.", + Description: "The description of the integration policy.", Type: schema.TypeString, Optional: true, }, "enabled": { - Description: "Enable the package policy.", + Description: "Enable the integration policy.", Type: schema.TypeBool, Optional: true, Computed: true, @@ -52,13 +52,13 @@ func ResourcePackagePolicy() *schema.Resource { Type: schema.TypeBool, Optional: true, }, - "package_name": { - Description: "The name of the package.", + "integration_name": { + Description: "The name of the integration package.", Type: schema.TypeString, Required: true, }, - "package_version": { - Description: "The version of the package.", + "integration_version": { + Description: "The version of the integration package.", Type: schema.TypeString, Required: true, }, @@ -98,7 +98,7 @@ func ResourcePackagePolicy() *schema.Resource { }, }, "vars_json": { - Description: "Package-level variables as JSON.", + Description: "Integration-level variables as JSON.", Type: schema.TypeString, ValidateFunc: validation.StringIsJSON, Computed: true, @@ -108,12 +108,12 @@ func ResourcePackagePolicy() *schema.Resource { } return &schema.Resource{ - Description: "Creates a new Fleet Package Policy. See https://www.elastic.co/guide/en/fleet/current/agent-policy.html", + Description: "Creates a new Fleet Integration Policy. See https://www.elastic.co/guide/en/fleet/current/add-integration-to-policy.html", - CreateContext: resourcePackagePolicyCreate, - ReadContext: resourcePackagePolicyRead, - UpdateContext: resourcePackagePolicyUpdate, - DeleteContext: resourcePackagePolicyDelete, + CreateContext: resourceIntegrationPolicyCreate, + ReadContext: resourceIntegrationPolicyRead, + UpdateContext: resourceIntegrationPolicyUpdate, + DeleteContext: resourceIntegrationPolicyDelete, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, @@ -123,7 +123,7 @@ func ResourcePackagePolicy() *schema.Resource { } } -func resourcePackagePolicyCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourceIntegrationPolicyCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { fleetClient, diags := getFleetClient(d, meta) if diags.HasError() { return diags @@ -137,8 +137,8 @@ func resourcePackagePolicyCreate(ctx context.Context, d *schema.ResourceData, me PolicyId: d.Get("agent_policy_id").(string), Name: d.Get("name").(string), } - req.Package.Name = d.Get("package_name").(string) - req.Package.Version = d.Get("package_version").(string) + req.Package.Name = d.Get("integration_name").(string) + req.Package.Version = d.Get("integration_version").(string) if value := d.Get("policy_id").(string); value != "" { req.Id = &value @@ -204,10 +204,10 @@ func resourcePackagePolicyCreate(ctx context.Context, d *schema.ResourceData, me return diag.FromErr(err) } - return resourcePackagePolicyRead(ctx, d, meta) + return resourceIntegrationPolicyRead(ctx, d, meta) } -func resourcePackagePolicyUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourceIntegrationPolicyUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { fleetClient, diags := getFleetClient(d, meta) if diags.HasError() { return diags @@ -217,8 +217,8 @@ func resourcePackagePolicyUpdate(ctx context.Context, d *schema.ResourceData, me PolicyId: d.Get("agent_policy_id").(string), Name: d.Get("name").(string), } - req.Package.Name = d.Get("package_name").(string) - req.Package.Version = d.Get("package_version").(string) + req.Package.Name = d.Get("integration_name").(string) + req.Package.Version = d.Get("integration_version").(string) if value := d.Get("policy_id").(string); value != "" { req.Id = &value @@ -278,10 +278,10 @@ func resourcePackagePolicyUpdate(ctx context.Context, d *schema.ResourceData, me return diags } - return resourcePackagePolicyRead(ctx, d, meta) + return resourceIntegrationPolicyRead(ctx, d, meta) } -func resourcePackagePolicyRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourceIntegrationPolicyRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { fleetClient, diags := getFleetClient(d, meta) if diags.HasError() { return diags @@ -304,10 +304,10 @@ func resourcePackagePolicyRead(ctx context.Context, d *schema.ResourceData, meta if err := d.Set("namespace", pkgPolicy.Namespace); err != nil { return diag.FromErr(err) } - if err := d.Set("package_name", pkgPolicy.Package.Name); err != nil { + if err := d.Set("integration_name", pkgPolicy.Package.Name); err != nil { return diag.FromErr(err) } - if err := d.Set("package_version", pkgPolicy.Package.Version); err != nil { + if err := d.Set("integration_version", pkgPolicy.Package.Version); err != nil { return diag.FromErr(err) } if err := d.Set("agent_policy_id", pkgPolicy.PolicyId); err != nil { @@ -371,7 +371,7 @@ func resourcePackagePolicyRead(ctx context.Context, d *schema.ResourceData, meta return nil } -func resourcePackagePolicyDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourceIntegrationPolicyDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { fleetClient, diags := getFleetClient(d, meta) if diags.HasError() { return diags diff --git a/internal/fleet/integration_policy_resource_test.go b/internal/fleet/integration_policy_resource_test.go new file mode 100644 index 000000000..b1ad68a52 --- /dev/null +++ b/internal/fleet/integration_policy_resource_test.go @@ -0,0 +1,204 @@ +package fleet_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/go-version" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/elastic/terraform-provider-elasticstack/internal/acctest" + "github.com/elastic/terraform-provider-elasticstack/internal/clients" + "github.com/elastic/terraform-provider-elasticstack/internal/clients/fleet" + "github.com/elastic/terraform-provider-elasticstack/internal/versionutils" +) + +var minVersionIntegrationPolicy = version.Must(version.NewVersion("8.10.0")) + +func TestAccResourceIntegrationPolicy(t *testing.T) { + policyName := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + CheckDestroy: checkResourceIntegrationPolicyDestroy, + ProtoV6ProviderFactories: acctest.Providers, + Steps: []resource.TestStep{ + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionIntegrationPolicy), + Config: testAccResourceIntegrationPolicyCreate(policyName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "name", policyName), + resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "description", "IntegrationPolicyTest Policy"), + resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "integration_name", "tcp"), + resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "integration_version", "1.16.0"), + resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "input.0.input_id", "tcp-tcp"), + resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "input.0.enabled", "true"), + resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "input.0.streams_json", "{\"tcp.generic\":{\"enabled\":true,\"vars\":{\"custom\":\"\",\"data_stream.dataset\":\"tcp.generic\",\"listen_address\":\"localhost\",\"listen_port\":8080,\"ssl\":\"#certificate: |\\n# -----BEGIN CERTIFICATE-----\\n# ...\\n# -----END CERTIFICATE-----\\n#key: |\\n# -----BEGIN PRIVATE KEY-----\\n# ...\\n# -----END PRIVATE KEY-----\\n\",\"syslog_options\":\"field: message\\n#format: auto\\n#timezone: Local\\n\",\"tags\":[]}}}"), + ), + }, + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionIntegrationPolicy), + Config: testAccResourceIntegrationPolicyUpdate(policyName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "name", policyName), + resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "description", "Updated Integration Policy"), + resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "integration_name", "tcp"), + resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "integration_version", "1.16.0"), + resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "input.0.input_id", "tcp-tcp"), + resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "input.0.enabled", "true"), + resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "input.0.streams_json", "{\"tcp.generic\":{\"enabled\":true,\"vars\":{\"custom\":\"\",\"data_stream.dataset\":\"tcp.generic\",\"listen_address\":\"localhost\",\"listen_port\":8085,\"ssl\":\"#certificate: |\\n# -----BEGIN CERTIFICATE-----\\n# ...\\n# -----END CERTIFICATE-----\\n#key: |\\n# -----BEGIN PRIVATE KEY-----\\n# ...\\n# -----END PRIVATE KEY-----\\n\",\"syslog_options\":\"field: message\\n#format: auto\\n#timezone: Local\\n\",\"tags\":[]}}}"), + ), + }, + }, + }) +} + +func checkResourceIntegrationPolicyDestroy(s *terraform.State) error { + client, err := clients.NewAcceptanceTestingClient() + if err != nil { + return err + } + + fleetClient, err := client.GetFleetClient() + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + switch rs.Type { + case "elasticstack_fleet_integration_policy": + integrationPolicy, diag := fleet.ReadPackagePolicy(context.Background(), fleetClient, rs.Primary.ID) + if diag.HasError() { + return fmt.Errorf(diag[0].Summary) + } + if integrationPolicy != nil { + return fmt.Errorf("integration policy id=%v still exists, but it should have been removed", rs.Primary.ID) + } + case "elasticstack_fleet_agent_policy": + agentPolicy, diag := fleet.ReadAgentPolicy(context.Background(), fleetClient, rs.Primary.ID) + if diag.HasError() { + return fmt.Errorf(diag[0].Summary) + } + if agentPolicy != nil { + return fmt.Errorf("agent policy id=%v still exists, but it should have been removed", rs.Primary.ID) + } + default: + continue + } + + } + return nil +} + +func testAccResourceIntegrationPolicyCreate(id string) string { + return fmt.Sprintf(` +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_fleet_integration" "test_policy" { + name = "tcp" + version = "1.16.0" + force = true +} + +resource "elasticstack_fleet_agent_policy" "test_policy" { + name = "%s Agent Policy" + namespace = "default" + description = "IntegrationPolicyTest Agent Policy" + monitor_logs = true + monitor_metrics = true + skip_destroy = false +} + +data "elasticstack_fleet_enrollment_tokens" "test_policy" { + policy_id = elasticstack_fleet_agent_policy.test_policy.policy_id +} + +resource "elasticstack_fleet_integration_policy" "test_policy" { + name = "%s" + namespace = "default" + description = "IntegrationPolicyTest Policy" + agent_policy_id = elasticstack_fleet_agent_policy.test_policy.policy_id + integration_name = elasticstack_fleet_integration.test_policy.name + integration_version = elasticstack_fleet_integration.test_policy.version + + input { + input_id = "tcp-tcp" + streams_json = jsonencode({ + "tcp.generic": { + "enabled": true, + "vars": { + "listen_address": "localhost", + "listen_port": 8080, + "data_stream.dataset": "tcp.generic", + "tags": [], + "syslog_options": "field: message\n#format: auto\n#timezone: Local\n", + "ssl": "#certificate: |\n# -----BEGIN CERTIFICATE-----\n# ...\n# -----END CERTIFICATE-----\n#key: |\n# -----BEGIN PRIVATE KEY-----\n# ...\n# -----END PRIVATE KEY-----\n", + "custom": "" + } + } + }) + } +} +`, id, id) +} + +func testAccResourceIntegrationPolicyUpdate(id string) string { + return fmt.Sprintf(` +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_fleet_integration" "test_policy" { + name = "tcp" + version = "1.16.0" + force = true +} + +resource "elasticstack_fleet_agent_policy" "test_policy" { + name = "%s Agent Policy" + namespace = "default" + description = "IntegrationPolicyTest Agent Policy" + monitor_logs = true + monitor_metrics = true + skip_destroy = false +} + +data "elasticstack_fleet_enrollment_tokens" "test_policy" { + policy_id = elasticstack_fleet_agent_policy.test_policy.policy_id +} + +resource "elasticstack_fleet_integration_policy" "test_policy" { + name = "%s" + namespace = "default" + description = "Updated Integration Policy" + agent_policy_id = elasticstack_fleet_agent_policy.test_policy.policy_id + integration_name = elasticstack_fleet_integration.test_policy.name + integration_version = elasticstack_fleet_integration.test_policy.version + + input { + input_id = "tcp-tcp" + streams_json = jsonencode({ + "tcp.generic": { + "enabled": true, + "vars": { + "listen_address": "localhost", + "listen_port": 8085, + "data_stream.dataset": "tcp.generic", + "tags": [], + "syslog_options": "field: message\n#format: auto\n#timezone: Local\n", + "ssl": "#certificate: |\n# -----BEGIN CERTIFICATE-----\n# ...\n# -----END CERTIFICATE-----\n#key: |\n# -----BEGIN PRIVATE KEY-----\n# ...\n# -----END PRIVATE KEY-----\n", + "custom": "" + } + } + }) + } +} +`, id, id) +} diff --git a/internal/fleet/package_resource.go b/internal/fleet/integration_resource.go similarity index 66% rename from internal/fleet/package_resource.go rename to internal/fleet/integration_resource.go index 603b9538b..71013064e 100644 --- a/internal/fleet/package_resource.go +++ b/internal/fleet/integration_resource.go @@ -17,16 +17,16 @@ func getPackageID(name, version string) string { return *hash } -func ResourcePackage() *schema.Resource { +func ResourceIntegration() *schema.Resource { packageSchema := map[string]*schema.Schema{ "name": { - Description: "The package name.", + Description: "The integration package name.", Type: schema.TypeString, ForceNew: true, Required: true, }, "version": { - Description: "The package version.", + Description: "The integration package version.", Type: schema.TypeString, ForceNew: true, Required: true, @@ -37,19 +37,19 @@ func ResourcePackage() *schema.Resource { Optional: true, }, "skip_destroy": { - Description: "Set to true if you do not wish the package to be uninstalled at destroy time, and instead just remove the package from the Terraform state.", + Description: "Set to true if you do not wish the integration package to be uninstalled at destroy time, and instead just remove the integration package from the Terraform state.", Type: schema.TypeBool, Optional: true, }, } return &schema.Resource{ - Description: "Manage installation of a Fleet package.", + Description: "Manage installation of a Fleet integration package.", - CreateContext: resourcePackageInstall, - ReadContext: resourcePackageRead, - UpdateContext: resourcePackageInstall, - DeleteContext: resourcePackageDelete, + CreateContext: resourceIntegrationInstall, + ReadContext: resourceIntegrationRead, + UpdateContext: resourceIntegrationInstall, + DeleteContext: resourceIntegrationDelete, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, @@ -59,7 +59,7 @@ func ResourcePackage() *schema.Resource { } } -func resourcePackageInstall(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourceIntegrationInstall(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { fleetClient, diags := getFleetClient(d, meta) if diags.HasError() { return diags @@ -75,10 +75,10 @@ func resourcePackageInstall(ctx context.Context, d *schema.ResourceData, meta in return diags } - return resourcePackageRead(ctx, d, meta) + return resourceIntegrationRead(ctx, d, meta) } -func resourcePackageRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourceIntegrationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { fleetClient, diags := getFleetClient(d, meta) if diags.HasError() { return diags @@ -96,13 +96,13 @@ func resourcePackageRead(ctx context.Context, d *schema.ResourceData, meta inter return nil } -func resourcePackageDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourceIntegrationDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { name := d.Get("name").(string) version := d.Get("version").(string) force := d.Get("force").(bool) if d.Get("skip_destroy").(bool) { - tflog.Debug(ctx, "Skipping uninstall of Package", map[string]interface{}{"name": name, "version": version}) + tflog.Debug(ctx, "Skipping uninstall of integration package", map[string]interface{}{"name": name, "version": version}) return nil } diff --git a/internal/fleet/package_resource_test.go b/internal/fleet/integration_resource_test.go similarity index 61% rename from internal/fleet/package_resource_test.go rename to internal/fleet/integration_resource_test.go index a6900941a..adec1ac3c 100644 --- a/internal/fleet/package_resource_test.go +++ b/internal/fleet/integration_resource_test.go @@ -10,15 +10,15 @@ import ( "github.com/elastic/terraform-provider-elasticstack/internal/versionutils" ) -var minVersionPackage = version.Must(version.NewVersion("8.6.0")) +var minVersionIntegration = version.Must(version.NewVersion("8.6.0")) -const packageConfig = ` +const integrationConfig = ` provider "elasticstack" { elasticsearch {} kibana {} } -resource "elasticstack_fleet_package" "test_package" { +resource "elasticstack_fleet_integration" "test_integration" { name = "tcp" version = "1.16.0" force = true @@ -26,17 +26,17 @@ resource "elasticstack_fleet_package" "test_package" { } ` -func TestAccResourcePackage(t *testing.T) { +func TestAccResourceIntegration(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ProtoV6ProviderFactories: acctest.Providers, Steps: []resource.TestStep{ { - SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionPackage), - Config: packageConfig, + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionIntegration), + Config: integrationConfig, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("elasticstack_fleet_package.test_package", "name", "tcp"), - resource.TestCheckResourceAttr("elasticstack_fleet_package.test_package", "version", "1.16.0"), + resource.TestCheckResourceAttr("elasticstack_fleet_integration.test_integration", "name", "tcp"), + resource.TestCheckResourceAttr("elasticstack_fleet_integration.test_integration", "version", "1.16.0"), ), }, }, diff --git a/internal/fleet/package_policy_resource_test.go b/internal/fleet/package_policy_resource_test.go deleted file mode 100644 index 89702e4a7..000000000 --- a/internal/fleet/package_policy_resource_test.go +++ /dev/null @@ -1,204 +0,0 @@ -package fleet_test - -import ( - "context" - "fmt" - "testing" - - "github.com/hashicorp/go-version" - sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - "github.com/elastic/terraform-provider-elasticstack/internal/acctest" - "github.com/elastic/terraform-provider-elasticstack/internal/clients" - "github.com/elastic/terraform-provider-elasticstack/internal/clients/fleet" - "github.com/elastic/terraform-provider-elasticstack/internal/versionutils" -) - -var minVersionPackagePolicy = version.Must(version.NewVersion("8.10.0")) - -func TestAccResourcePackagePolicy(t *testing.T) { - policyName := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - CheckDestroy: checkResourcePackagePolicyDestroy, - ProtoV6ProviderFactories: acctest.Providers, - Steps: []resource.TestStep{ - { - SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionPackagePolicy), - Config: testAccResourcePackagePolicyCreate(policyName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("elasticstack_fleet_package_policy.test_policy", "name", policyName), - resource.TestCheckResourceAttr("elasticstack_fleet_package_policy.test_policy", "description", "PackagePolicyTest Policy"), - resource.TestCheckResourceAttr("elasticstack_fleet_package_policy.test_policy", "package_name", "tcp"), - resource.TestCheckResourceAttr("elasticstack_fleet_package_policy.test_policy", "package_version", "1.16.0"), - resource.TestCheckResourceAttr("elasticstack_fleet_package_policy.test_policy", "input.0.input_id", "tcp-tcp"), - resource.TestCheckResourceAttr("elasticstack_fleet_package_policy.test_policy", "input.0.enabled", "true"), - resource.TestCheckResourceAttr("elasticstack_fleet_package_policy.test_policy", "input.0.streams_json", "{\"tcp.generic\":{\"enabled\":true,\"vars\":{\"custom\":\"\",\"data_stream.dataset\":\"tcp.generic\",\"listen_address\":\"localhost\",\"listen_port\":8080,\"ssl\":\"#certificate: |\\n# -----BEGIN CERTIFICATE-----\\n# ...\\n# -----END CERTIFICATE-----\\n#key: |\\n# -----BEGIN PRIVATE KEY-----\\n# ...\\n# -----END PRIVATE KEY-----\\n\",\"syslog_options\":\"field: message\\n#format: auto\\n#timezone: Local\\n\",\"tags\":[]}}}"), - ), - }, - { - SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionPackagePolicy), - Config: testAccResourcePackagePolicyUpdate(policyName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("elasticstack_fleet_package_policy.test_policy", "name", policyName), - resource.TestCheckResourceAttr("elasticstack_fleet_package_policy.test_policy", "description", "Updated Package Policy"), - resource.TestCheckResourceAttr("elasticstack_fleet_package_policy.test_policy", "package_name", "tcp"), - resource.TestCheckResourceAttr("elasticstack_fleet_package_policy.test_policy", "package_version", "1.16.0"), - resource.TestCheckResourceAttr("elasticstack_fleet_package_policy.test_policy", "input.0.input_id", "tcp-tcp"), - resource.TestCheckResourceAttr("elasticstack_fleet_package_policy.test_policy", "input.0.enabled", "true"), - resource.TestCheckResourceAttr("elasticstack_fleet_package_policy.test_policy", "input.0.streams_json", "{\"tcp.generic\":{\"enabled\":true,\"vars\":{\"custom\":\"\",\"data_stream.dataset\":\"tcp.generic\",\"listen_address\":\"localhost\",\"listen_port\":8085,\"ssl\":\"#certificate: |\\n# -----BEGIN CERTIFICATE-----\\n# ...\\n# -----END CERTIFICATE-----\\n#key: |\\n# -----BEGIN PRIVATE KEY-----\\n# ...\\n# -----END PRIVATE KEY-----\\n\",\"syslog_options\":\"field: message\\n#format: auto\\n#timezone: Local\\n\",\"tags\":[]}}}"), - ), - }, - }, - }) -} - -func checkResourcePackagePolicyDestroy(s *terraform.State) error { - client, err := clients.NewAcceptanceTestingClient() - if err != nil { - return err - } - - fleetClient, err := client.GetFleetClient() - if err != nil { - return err - } - - for _, rs := range s.RootModule().Resources { - switch rs.Type { - case "elasticstack_fleet_package_policy": - packagePolicy, diag := fleet.ReadPackagePolicy(context.Background(), fleetClient, rs.Primary.ID) - if diag.HasError() { - return fmt.Errorf(diag[0].Summary) - } - if packagePolicy != nil { - return fmt.Errorf("package policy id=%v still exists, but it should have been removed", rs.Primary.ID) - } - case "elasticstack_fleet_agent_policy": - agentPolicy, diag := fleet.ReadAgentPolicy(context.Background(), fleetClient, rs.Primary.ID) - if diag.HasError() { - return fmt.Errorf(diag[0].Summary) - } - if agentPolicy != nil { - return fmt.Errorf("agent policy id=%v still exists, but it should have been removed", rs.Primary.ID) - } - default: - continue - } - - } - return nil -} - -func testAccResourcePackagePolicyCreate(id string) string { - return fmt.Sprintf(` -provider "elasticstack" { - elasticsearch {} - kibana {} -} - -resource "elasticstack_fleet_package" "test_policy" { - name = "tcp" - version = "1.16.0" - force = true -} - -resource "elasticstack_fleet_agent_policy" "test_policy" { - name = "%s Agent Policy" - namespace = "default" - description = "PackagePolicyTest Agent Policy" - monitor_logs = true - monitor_metrics = true - skip_destroy = false -} - -data "elasticstack_fleet_enrollment_tokens" "test_policy" { - policy_id = elasticstack_fleet_agent_policy.test_policy.policy_id -} - -resource "elasticstack_fleet_package_policy" "test_policy" { - name = "%s" - namespace = "default" - description = "PackagePolicyTest Policy" - agent_policy_id = elasticstack_fleet_agent_policy.test_policy.policy_id - package_name = elasticstack_fleet_package.test_policy.name - package_version = elasticstack_fleet_package.test_policy.version - - input { - input_id = "tcp-tcp" - streams_json = jsonencode({ - "tcp.generic": { - "enabled": true, - "vars": { - "listen_address": "localhost", - "listen_port": 8080, - "data_stream.dataset": "tcp.generic", - "tags": [], - "syslog_options": "field: message\n#format: auto\n#timezone: Local\n", - "ssl": "#certificate: |\n# -----BEGIN CERTIFICATE-----\n# ...\n# -----END CERTIFICATE-----\n#key: |\n# -----BEGIN PRIVATE KEY-----\n# ...\n# -----END PRIVATE KEY-----\n", - "custom": "" - } - } - }) - } -} -`, id, id) -} - -func testAccResourcePackagePolicyUpdate(id string) string { - return fmt.Sprintf(` -provider "elasticstack" { - elasticsearch {} - kibana {} -} - -resource "elasticstack_fleet_package" "test_policy" { - name = "tcp" - version = "1.16.0" - force = true -} - -resource "elasticstack_fleet_agent_policy" "test_policy" { - name = "%s Agent Policy" - namespace = "default" - description = "PackagePolicyTest Agent Policy" - monitor_logs = true - monitor_metrics = true - skip_destroy = false -} - -data "elasticstack_fleet_enrollment_tokens" "test_policy" { - policy_id = elasticstack_fleet_agent_policy.test_policy.policy_id -} - -resource "elasticstack_fleet_package_policy" "test_policy" { - name = "%s" - namespace = "default" - description = "Updated Package Policy" - agent_policy_id = elasticstack_fleet_agent_policy.test_policy.policy_id - package_name = elasticstack_fleet_package.test_policy.name - package_version = elasticstack_fleet_package.test_policy.version - - input { - input_id = "tcp-tcp" - streams_json = jsonencode({ - "tcp.generic": { - "enabled": true, - "vars": { - "listen_address": "localhost", - "listen_port": 8085, - "data_stream.dataset": "tcp.generic", - "tags": [], - "syslog_options": "field: message\n#format: auto\n#timezone: Local\n", - "ssl": "#certificate: |\n# -----BEGIN CERTIFICATE-----\n# ...\n# -----END CERTIFICATE-----\n#key: |\n# -----BEGIN PRIVATE KEY-----\n# ...\n# -----END PRIVATE KEY-----\n", - "custom": "" - } - } - }) - } -} -`, id, id) -} diff --git a/provider/provider.go b/provider/provider.go index 59bcc4ee5..ac41b9cf4 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -82,7 +82,7 @@ func New(version string) *schema.Provider { "elasticstack_kibana_security_role": kibana.DataSourceRole(), "elasticstack_fleet_enrollment_tokens": fleet.DataSourceEnrollmentTokens(), - "elasticstack_fleet_package": fleet.DataSourcePackage(), + "elasticstack_fleet_integration": fleet.DataSourceIntegration(), }, ResourcesMap: map[string]*schema.Resource{ "elasticstack_elasticsearch_cluster_settings": cluster.ResourceSettings(), @@ -111,11 +111,11 @@ func New(version string) *schema.Provider { "elasticstack_kibana_security_role": kibana.ResourceRole(), "elasticstack_kibana_slo": kibana.ResourceSlo(), - "elasticstack_fleet_agent_policy": fleet.ResourceAgentPolicy(), - "elasticstack_fleet_output": fleet.ResourceOutput(), - "elasticstack_fleet_server_host": fleet.ResourceFleetServerHost(), - "elasticstack_fleet_package": fleet.ResourcePackage(), - "elasticstack_fleet_package_policy": fleet.ResourcePackagePolicy(), + "elasticstack_fleet_agent_policy": fleet.ResourceAgentPolicy(), + "elasticstack_fleet_output": fleet.ResourceOutput(), + "elasticstack_fleet_server_host": fleet.ResourceFleetServerHost(), + "elasticstack_fleet_integration": fleet.ResourceIntegration(), + "elasticstack_fleet_integration_policy": fleet.ResourceIntegrationPolicy(), }, } diff --git a/templates/data-sources/fleet_package.md.tmpl b/templates/data-sources/fleet_integration.md.tmpl similarity index 79% rename from templates/data-sources/fleet_package.md.tmpl rename to templates/data-sources/fleet_integration.md.tmpl index ca8d14907..e212bb541 100644 --- a/templates/data-sources/fleet_package.md.tmpl +++ b/templates/data-sources/fleet_integration.md.tmpl @@ -1,12 +1,12 @@ --- subcategory: "Fleet" layout: "" -page_title: "Elasticstack: elasticstack_fleet_package Data Source" +page_title: "Elasticstack: elasticstack_fleet_integration Data Source" description: |- Gets information about a Fleet integration package. --- -# Data Source: elasticstack_fleet_package +# Data Source: elasticstack_fleet_integration This data source provides information about a Fleet integration package. Currently, the data source will retrieve the latest available version of the package. Version @@ -21,6 +21,6 @@ should be set to `true`. ## Example Usage -{{ tffile "examples/data-sources/elasticstack_fleet_package/data-source.tf" }} +{{ tffile "examples/data-sources/elasticstack_fleet_integration/data-source.tf" }} {{ .SchemaMarkdown | trimspace }} diff --git a/templates/resources/fleet_package.md.tmpl b/templates/resources/fleet_integration.md.tmpl similarity index 74% rename from templates/resources/fleet_package.md.tmpl rename to templates/resources/fleet_integration.md.tmpl index d5807f951..e0e089047 100644 --- a/templates/resources/fleet_package.md.tmpl +++ b/templates/resources/fleet_integration.md.tmpl @@ -1,12 +1,12 @@ --- subcategory: "Fleet" layout: "" -page_title: "Elasticstack: elasticstack_fleet_package Resource" +page_title: "Elasticstack: elasticstack_fleet_integration Resource" description: |- Installs or uninstalls a Fleet integration package. --- -# Resource: elasticstack_fleet_package +# Resource: elasticstack_fleet_integration Installs or uninstalls a Fleet integration package. The Kibana Fleet UI can be used to view available packages. Additional information for managing integration @@ -17,6 +17,6 @@ set `skip_destroy` to `true`. ## Example Usage -{{ tffile "examples/resources/elasticstack_fleet_package/resource.tf" }} +{{ tffile "examples/resources/elasticstack_fleet_integration/resource.tf" }} {{ .SchemaMarkdown | trimspace }} diff --git a/templates/resources/fleet_package_policy.md.tmpl b/templates/resources/fleet_integration_policy.md.tmpl similarity index 64% rename from templates/resources/fleet_package_policy.md.tmpl rename to templates/resources/fleet_integration_policy.md.tmpl index 886b4a67e..7e9274d62 100644 --- a/templates/resources/fleet_package_policy.md.tmpl +++ b/templates/resources/fleet_integration_policy.md.tmpl @@ -1,14 +1,14 @@ --- subcategory: "Fleet" layout: "" -page_title: "Elasticstack: elasticstack_fleet_package_policy Resource" +page_title: "Elasticstack: elasticstack_fleet_integration_policy Resource" description: |- - Creates or updates a Fleet Package Policy. + Creates or updates a Fleet Integration Policy. --- -# Resource: elasticstack_fleet_package_policy +# Resource: elasticstack_fleet_integration_policy -Creates or updates a Fleet Package Policy. +Creates or updates a Fleet Integration Policy. It is highly recommended that all inputs and streams are provided in the Terraform plan, even if some are disabled. Otherwise, differences may appear @@ -21,7 +21,7 @@ values need to be provided for inputs and their streams. ## Example Usage -{{ tffile "examples/resources/elasticstack_fleet_package_policy/resource.tf" }} +{{ tffile "examples/resources/elasticstack_fleet_integration_policy/resource.tf" }} {{ .SchemaMarkdown | trimspace }} @@ -29,4 +29,4 @@ values need to be provided for inputs and their streams. Import is supported using the following syntax: -{{ codefile "shell" "examples/resources/elasticstack_fleet_package_policy/import.sh" }} +{{ codefile "shell" "examples/resources/elasticstack_fleet_integration_policy/import.sh" }} From e30fda07fe2decd28a5f3eb1d056e9dbd9ca477e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20Haro?= Date: Mon, 20 Nov 2023 23:50:57 +0100 Subject: [PATCH 03/12] Kibana SLOs: use `spaceID` (#485) --- internal/clients/kibana/slo.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/clients/kibana/slo.go b/internal/clients/kibana/slo.go index 6b45ae79b..d09c4da40 100644 --- a/internal/clients/kibana/slo.go +++ b/internal/clients/kibana/slo.go @@ -19,7 +19,7 @@ func GetSlo(ctx context.Context, apiClient *clients.ApiClient, id, spaceID strin } ctxWithAuth := apiClient.SetSloAuthContext(ctx) - req := client.GetSloOp(ctxWithAuth, "default", id).KbnXsrf("true") + req := client.GetSloOp(ctxWithAuth, spaceID, id).KbnXsrf("true") sloRes, res, err := req.Execute() if res == nil { return nil, diag.FromErr(err) @@ -33,7 +33,7 @@ func GetSlo(ctx context.Context, apiClient *clients.ApiClient, id, spaceID strin defer res.Body.Close() - return sloResponseToModel("default", sloRes), utils.CheckHttpError(res, "Unable to get slo with ID "+string(id)) + return sloResponseToModel(spaceID, sloRes), utils.CheckHttpError(res, "Unable to get slo with ID "+string(id)) } func DeleteSlo(ctx context.Context, apiClient *clients.ApiClient, sloId string, spaceId string) diag.Diagnostics { From 586f97d3942836716ddfae7df3872634974ffdf5 Mon Sep 17 00:00:00 2001 From: Toby Brain Date: Tue, 21 Nov 2023 09:51:56 +1100 Subject: [PATCH 04/12] Fixup changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03f984f2b..6ab06bcf2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ### Fixed - Rename fleet package objects to `elasticstack_fleet_integration` and `elasticstack_fleet_integration_policy` ([#476](https://github.com/elastic/terraform-provider-elasticstack/pull/476)) +- Fix a provider crash when managing SLOs outside of the default Kibana space. ([#485](https://github.com/elastic/terraform-provider-elasticstack/pull/485)) ## [0.10.0] - 2023-11-02 From 6fcbbaadea45fd7d8b6eef9304271c271585ff9e Mon Sep 17 00:00:00 2001 From: Andrian Jardan <126670426+andrianjardan@users.noreply.github.com> Date: Thu, 23 Nov 2023 11:13:56 +0100 Subject: [PATCH 05/12] Kibana api key (#372) * Adding api key functionality for Kibana * Adding support for api_key for Kibana * Adding go-kibana-rest lib locally as it is abandoned by authors * update docs * added support for SLO client to use API keys * add auth interceptor to connectors client * added test case for Kibana API keys via provider * slight fix to table test * added fwschema * fix copy-pasta * some typos, generate docs * manually patch generated code for now * update specs * update new kb config from framework * added api key to provider tests * use built in jq * remove kibana api key env * API keys should cascade from ES->Kibana->Fleet * update rules doc --------- Co-authored-by: Jean-Louis Leysens Co-authored-by: Toby Brain --- .github/workflows/test.yml | 10 + Makefile | 5 + docs/index.md | 2 + docs/resources/kibana_alerting_rule.md | 7 + generated/alerting/api/openapi.yaml | 2 +- generated/alerting/api_alerting.go | 52 +-- generated/alerting/client.go | 5 + generated/slo/api/openapi.yaml | 2 +- generated/slo/api_slo.go | 16 +- go.mod | 2 + internal/clients/api_client.go | 55 ++- internal/clients/config/base.go | 1 + internal/clients/config/fleet_test.go | 2 +- internal/clients/config/kibana.go | 9 + internal/clients/config/kibana_test.go | 34 +- internal/clients/config/provider.go | 1 + internal/kibana/alerting_test.go | 2 + internal/schema/connection.go | 17 + .../.github/workflows/workflow.yml | 51 +++ libs/go-kibana-rest/.gitignore | 12 + libs/go-kibana-rest/.theia/launch.json | 12 + libs/go-kibana-rest/LICENSE | 21 + libs/go-kibana-rest/Makefile | 18 + libs/go-kibana-rest/README.md | 337 ++++++++++++++ libs/go-kibana-rest/_examples/sample.go | 283 ++++++++++++ libs/go-kibana-rest/coverage.txt | 354 +++++++++++++++ libs/go-kibana-rest/doc.go | 4 + libs/go-kibana-rest/docker-compose.yml | 21 + .../fixtures/kibana-dashboard.json | 371 ++++++++++++++++ libs/go-kibana-rest/go.mod | 25 ++ libs/go-kibana-rest/go.sum | 118 +++++ libs/go-kibana-rest/kbapi/api._.go | 114 +++++ .../kbapi/api.kibana_dashboard.go | 114 +++++ .../kbapi/api.kibana_dashboard_test.go | 46 ++ .../kbapi/api.kibana_logstash_pipeline.go | 182 ++++++++ .../api.kibana_logstash_pipeline_test.go | 41 ++ .../kbapi/api.kibana_role_management.go | 190 ++++++++ .../kbapi/api.kibana_role_management_test.go | 55 +++ .../kbapi/api.kibana_save_object.go | 411 ++++++++++++++++++ .../kbapi/api.kibana_save_object_test.go | 152 +++++++ .../kbapi/api.kibana_shorten_url.go | 78 ++++ .../kbapi/api.kibana_shorten_url_test.go | 20 + .../go-kibana-rest/kbapi/api.kibana_spaces.go | 274 ++++++++++++ .../kbapi/api.kibana_spaces_test.go | 59 +++ .../go-kibana-rest/kbapi/api.kibana_status.go | 43 ++ .../kbapi/api.kibana_status_test.go | 13 + libs/go-kibana-rest/kbapi/api_test.go | 82 ++++ libs/go-kibana-rest/kbapi/doc.go | 4 + libs/go-kibana-rest/kbapi/error.go | 24 + libs/go-kibana-rest/kbapi/error_test.go | 10 + libs/go-kibana-rest/kibana.go | 63 +++ libs/go-kibana-rest/kibana_test.go | 57 +++ provider/provider_test.go | 89 +++- templates/index.md.tmpl | 1 + .../resources/kibana_alerting_rule.md.tmpl | 7 + 55 files changed, 3917 insertions(+), 63 deletions(-) create mode 100644 libs/go-kibana-rest/.github/workflows/workflow.yml create mode 100644 libs/go-kibana-rest/.gitignore create mode 100644 libs/go-kibana-rest/.theia/launch.json create mode 100644 libs/go-kibana-rest/LICENSE create mode 100644 libs/go-kibana-rest/Makefile create mode 100644 libs/go-kibana-rest/README.md create mode 100644 libs/go-kibana-rest/_examples/sample.go create mode 100644 libs/go-kibana-rest/coverage.txt create mode 100644 libs/go-kibana-rest/doc.go create mode 100644 libs/go-kibana-rest/docker-compose.yml create mode 100644 libs/go-kibana-rest/fixtures/kibana-dashboard.json create mode 100644 libs/go-kibana-rest/go.mod create mode 100644 libs/go-kibana-rest/go.sum create mode 100644 libs/go-kibana-rest/kbapi/api._.go create mode 100644 libs/go-kibana-rest/kbapi/api.kibana_dashboard.go create mode 100644 libs/go-kibana-rest/kbapi/api.kibana_dashboard_test.go create mode 100644 libs/go-kibana-rest/kbapi/api.kibana_logstash_pipeline.go create mode 100644 libs/go-kibana-rest/kbapi/api.kibana_logstash_pipeline_test.go create mode 100644 libs/go-kibana-rest/kbapi/api.kibana_role_management.go create mode 100644 libs/go-kibana-rest/kbapi/api.kibana_role_management_test.go create mode 100644 libs/go-kibana-rest/kbapi/api.kibana_save_object.go create mode 100644 libs/go-kibana-rest/kbapi/api.kibana_save_object_test.go create mode 100644 libs/go-kibana-rest/kbapi/api.kibana_shorten_url.go create mode 100644 libs/go-kibana-rest/kbapi/api.kibana_shorten_url_test.go create mode 100644 libs/go-kibana-rest/kbapi/api.kibana_spaces.go create mode 100644 libs/go-kibana-rest/kbapi/api.kibana_spaces_test.go create mode 100644 libs/go-kibana-rest/kbapi/api.kibana_status.go create mode 100644 libs/go-kibana-rest/kbapi/api.kibana_status_test.go create mode 100644 libs/go-kibana-rest/kbapi/api_test.go create mode 100644 libs/go-kibana-rest/kbapi/doc.go create mode 100644 libs/go-kibana-rest/kbapi/error.go create mode 100644 libs/go-kibana-rest/kbapi/error_test.go create mode 100644 libs/go-kibana-rest/kibana.go create mode 100644 libs/go-kibana-rest/kibana_test.go diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3e5882907..014c1f3c7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -121,6 +121,15 @@ jobs: KIBANA_SYSTEM_USERNAME: ${{ env.KIBANA_SYSTEM_USERNAME }} KIBANA_SYSTEM_PASSWORD: ${{ env.KIBANA_SYSTEM_PASSWORD }} + - id: get-api-key + name: Get ES API key + run: |- + echo "apikey=$(make create-es-api-key | jq -r .encoded)" >> "$GITHUB_OUTPUT" + env: + ELASTICSEARCH_ENDPOINTS: "http://localhost:9200" + ELASTICSEARCH_USERNAME: "elastic" + ELASTICSEARCH_PASSWORD: ${{ env.ELASTIC_PASSWORD }} + - name: TF acceptance tests timeout-minutes: 10 run: make testacc @@ -131,3 +140,4 @@ jobs: ELASTICSEARCH_USERNAME: "elastic" ELASTICSEARCH_PASSWORD: ${{ env.ELASTIC_PASSWORD }} KIBANA_ENDPOINT: "http://localhost:5601" + KIBANA_API_KEY: ${{ steps.get-api-key.outputs.apikey }} diff --git a/Makefile b/Makefile index 96411111b..d7b159b58 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,7 @@ KIBANA_NAME ?= terraform-elasticstack-kb KIBANA_ENDPOINT ?= http://$(KIBANA_NAME):5601 KIBANA_SYSTEM_USERNAME ?= kibana_system KIBANA_SYSTEM_PASSWORD ?= password +KIBANA_API_KEY_NAME ?= kibana-api-key SOURCE_LOCATION ?= $(shell pwd) @@ -129,6 +130,10 @@ docker-network: ## Create a dedicated network for ES and test runs set-kibana-password: ## Sets the ES KIBANA_SYSTEM_USERNAME's password to KIBANA_SYSTEM_PASSWORD. This expects Elasticsearch to be available at localhost:9200 @ $(call retry, 10, curl -X POST -u $(ELASTICSEARCH_USERNAME):$(ELASTICSEARCH_PASSWORD) -H "Content-Type: application/json" http://localhost:9200/_security/user/$(KIBANA_SYSTEM_USERNAME)/_password -d "{\"password\":\"$(KIBANA_SYSTEM_PASSWORD)\"}" | grep -q "^{}") +.PHONY: create-es-api-key +create-es-api-key: ## Creates and outputs a new API Key. This expects Elasticsearch to be available at localhost:9200 + @ $(call retry, 10, curl -X POST -u $(ELASTICSEARCH_USERNAME):$(ELASTICSEARCH_PASSWORD) -H "Content-Type: application/json" http://localhost:9200/_security/api_key -d "{\"name\":\"$(KIBANA_API_KEY_NAME)\"}") + .PHONY: docker-clean docker-clean: ## Try to remove provisioned nodes and assigned network @ docker rm -f $(ELASTICSEARCH_NAME) $(KIBANA_NAME) || true diff --git a/docs/index.md b/docs/index.md index 66f6cd34c..87c2a1a75 100644 --- a/docs/index.md +++ b/docs/index.md @@ -92,6 +92,7 @@ Kibana resources will re-use any Elasticsearch credentials specified, these may - `KIBANA_USERNAME` - The username to use for Kibana authentication - `KIBANA_PASSWORD` - The password to use for Kibana authentication - `KIBANA_ENDPOINT` - The Kibana host to connect to +- `KIBANA_API_KEY` - An Elasticsearch API key to use instead of `KIBANA_USERNAME` and `KIBANA_PASSWORD` Fleet resources will re-use any Kibana or Elasticsearch credentials specified, these may be overridden with the following variables: - `FLEET_USERNAME` - The username to use for Kibana authentication @@ -179,6 +180,7 @@ Optional: Optional: +- `api_key` (String, Sensitive) API Key to use for authentication to Kibana - `endpoints` (List of String, Sensitive) A comma-separated list of endpoints where the terraform provider will point to, this must include the http(s) schema and port number. - `insecure` (Boolean) Disable TLS certificate validation - `password` (String, Sensitive) Password to use for API authentication to Kibana. diff --git a/docs/resources/kibana_alerting_rule.md b/docs/resources/kibana_alerting_rule.md index 3ac8ef4fe..66dcb1aa6 100644 --- a/docs/resources/kibana_alerting_rule.md +++ b/docs/resources/kibana_alerting_rule.md @@ -40,6 +40,13 @@ resource "elasticstack_kibana_alerting_rule" "example" { } ``` + +**NOTE:** `api_key` authentication is only supported for alerting rule resources from version 8.8.0 of the Elastic stack. Using an `api_key` will result in an error message like: + +``` +Could not create API key - Unsupported scheme "ApiKey" for granting API Key +``` + ## Schema diff --git a/generated/alerting/api/openapi.yaml b/generated/alerting/api/openapi.yaml index 327cf3829..291bcc645 100644 --- a/generated/alerting/api/openapi.yaml +++ b/generated/alerting/api/openapi.yaml @@ -3627,5 +3627,5 @@ components: type: http apiKeyAuth: in: header - name: ApiKey + name: Authorization type: apiKey diff --git a/generated/alerting/api_alerting.go b/generated/alerting/api_alerting.go index d8eeebe64..a36195a81 100644 --- a/generated/alerting/api_alerting.go +++ b/generated/alerting/api_alerting.go @@ -583,7 +583,7 @@ func (a *AlertingApiService) CreateRuleExecute(r ApiCreateRuleRequest) (*RuleRes } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -734,7 +734,7 @@ func (a *AlertingApiService) DeleteRuleExecute(r ApiDeleteRuleRequest) (*http.Re } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -876,7 +876,7 @@ func (a *AlertingApiService) DisableRuleExecute(r ApiDisableRuleRequest) (*http. } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -1018,7 +1018,7 @@ func (a *AlertingApiService) EnableRuleExecute(r ApiEnableRuleRequest) (*http.Re } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -1256,7 +1256,7 @@ func (a *AlertingApiService) FindRulesExecute(r ApiFindRulesRequest) (*FindRules } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -1384,7 +1384,7 @@ func (a *AlertingApiService) GetAlertingHealthExecute(r ApiGetAlertingHealthRequ } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -1516,7 +1516,7 @@ func (a *AlertingApiService) GetRuleExecute(r ApiGetRuleRequest) (*RuleResponseP } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -1655,7 +1655,7 @@ func (a *AlertingApiService) GetRuleTypesExecute(r ApiGetRuleTypesRequest) ([]Ge } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -1813,7 +1813,7 @@ func (a *AlertingApiService) LegacyCreateAlertExecute(r ApiLegacyCreateAlertRequ } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -1956,7 +1956,7 @@ func (a *AlertingApiService) LegacyDisableAlertExecute(r ApiLegacyDisableAlertRe } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -2090,7 +2090,7 @@ func (a *AlertingApiService) LegacyEnableAlertExecute(r ApiLegacyEnableAlertRequ } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -2321,7 +2321,7 @@ func (a *AlertingApiService) LegacyFindAlertsExecute(r ApiLegacyFindAlertsReques } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -2457,7 +2457,7 @@ func (a *AlertingApiService) LegacyGetAlertExecute(r ApiLegacyGetAlertRequest) ( } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -2589,7 +2589,7 @@ func (a *AlertingApiService) LegacyGetAlertTypesExecute(r ApiLegacyGetAlertTypes } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -2721,7 +2721,7 @@ func (a *AlertingApiService) LegacyGetAlertingHealthExecute(r ApiLegacyGetAlerti } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -2868,7 +2868,7 @@ func (a *AlertingApiService) LegacyMuteAlertInstanceExecute(r ApiLegacyMuteAlert } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -3002,7 +3002,7 @@ func (a *AlertingApiService) LegacyMuteAllAlertInstancesExecute(r ApiLegacyMuteA } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -3140,7 +3140,7 @@ func (a *AlertingApiService) LegacyUnmuteAlertInstanceExecute(r ApiLegacyUnmuteA } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -3274,7 +3274,7 @@ func (a *AlertingApiService) LegacyUnmuteAllAlertInstancesExecute(r ApiLegacyUnm } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -3423,7 +3423,7 @@ func (a *AlertingApiService) LegacyUpdateAlertExecute(r ApiLegacyUpdateAlertRequ } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -3566,7 +3566,7 @@ func (a *AlertingApiService) LegaryDeleteAlertExecute(r ApiLegaryDeleteAlertRequ } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -3701,7 +3701,7 @@ func (a *AlertingApiService) MuteAlertExecute(r ApiMuteAlertRequest) (*http.Resp } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -3832,7 +3832,7 @@ func (a *AlertingApiService) MuteAllAlertsExecute(r ApiMuteAllAlertsRequest) (*h } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -3967,7 +3967,7 @@ func (a *AlertingApiService) UnmuteAlertExecute(r ApiUnmuteAlertRequest) (*http. } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -4098,7 +4098,7 @@ func (a *AlertingApiService) UnmuteAllAlertsExecute(r ApiUnmuteAllAlertsRequest) } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -4243,7 +4243,7 @@ func (a *AlertingApiService) UpdateRuleExecute(r ApiUpdateRuleRequest) (*RuleRes } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } diff --git a/generated/alerting/client.go b/generated/alerting/client.go index 416200a38..94ccb6505 100644 --- a/generated/alerting/client.go +++ b/generated/alerting/client.go @@ -414,6 +414,11 @@ func (c *APIClient) prepareRequest( localVarRequest.SetBasicAuth(auth.UserName, auth.Password) } + // APIKey Authentication + if auth, ok := ctx.Value(ContextAPIKeys).(APIKey); ok { + localVarRequest.Header.Add("Authorization", "ApiKey "+auth.Key) + } + } for header, value := range c.cfg.DefaultHeader { diff --git a/generated/slo/api/openapi.yaml b/generated/slo/api/openapi.yaml index c5477b6b0..a3cd384b2 100644 --- a/generated/slo/api/openapi.yaml +++ b/generated/slo/api/openapi.yaml @@ -1550,5 +1550,5 @@ components: type: http apiKeyAuth: in: header - name: ApiKey + name: Authorization type: apiKey diff --git a/generated/slo/api_slo.go b/generated/slo/api_slo.go index fb518a05d..31d8c4ada 100644 --- a/generated/slo/api_slo.go +++ b/generated/slo/api_slo.go @@ -254,7 +254,7 @@ func (a *SloAPIService) CreateSloOpExecute(r ApiCreateSloOpRequest) (*CreateSloR } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -427,7 +427,7 @@ func (a *SloAPIService) DeleteSloOpExecute(r ApiDeleteSloOpRequest) (*http.Respo } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -591,7 +591,7 @@ func (a *SloAPIService) DisableSloOpExecute(r ApiDisableSloOpRequest) (*http.Res } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -755,7 +755,7 @@ func (a *SloAPIService) EnableSloOpExecute(r ApiEnableSloOpRequest) (*http.Respo } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -968,7 +968,7 @@ func (a *SloAPIService) FindSlosOpExecute(r ApiFindSlosOpRequest) (*FindSloRespo } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -1154,7 +1154,7 @@ func (a *SloAPIService) GetSloOpExecute(r ApiGetSloOpRequest) (*SloResponse, *ht } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -1337,7 +1337,7 @@ func (a *SloAPIService) HistoricalSummaryOpExecute(r ApiHistoricalSummaryOpReque } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } @@ -1513,7 +1513,7 @@ func (a *SloAPIService) UpdateSloOpExecute(r ApiUpdateSloOpRequest) (*SloRespons } else { key = apiKey.Key } - localVarHeaderParams["ApiKey"] = key + localVarHeaderParams["Authorization"] = key } } } diff --git a/go.mod b/go.mod index 306567115..3626e221b 100644 --- a/go.mod +++ b/go.mod @@ -73,3 +73,5 @@ require ( google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) + +replace github.com/disaster37/go-kibana-rest/v8 => ./libs/go-kibana-rest \ No newline at end of file diff --git a/internal/clients/api_client.go b/internal/clients/api_client.go index 8fb82f76d..993ba8333 100644 --- a/internal/clients/api_client.go +++ b/internal/clients/api_client.go @@ -226,17 +226,33 @@ func (a *ApiClient) GetFleetClient() (*fleet.Client, error) { } func (a *ApiClient) SetSloAuthContext(ctx context.Context) context.Context { - return context.WithValue(ctx, slo.ContextBasicAuth, slo.BasicAuth{ - UserName: a.kibanaConfig.Username, - Password: a.kibanaConfig.Password, - }) + if a.kibanaConfig.ApiKey != "" { + return context.WithValue(ctx, slo.ContextAPIKeys, map[string]slo.APIKey{ + "apiKeyAuth": { + Prefix: "ApiKey", + Key: a.kibanaConfig.ApiKey, + }}) + } else { + return context.WithValue(ctx, slo.ContextBasicAuth, slo.BasicAuth{ + UserName: a.kibanaConfig.Username, + Password: a.kibanaConfig.Password, + }) + } } func (a *ApiClient) SetAlertingAuthContext(ctx context.Context) context.Context { - return context.WithValue(ctx, alerting.ContextBasicAuth, alerting.BasicAuth{ - UserName: a.kibanaConfig.Username, - Password: a.kibanaConfig.Password, - }) + if a.kibanaConfig.ApiKey != "" { + return context.WithValue(ctx, alerting.ContextAPIKeys, map[string]alerting.APIKey{ + "apiKeyAuth": { + Prefix: "ApiKey", + Key: a.kibanaConfig.ApiKey, + }}) + } else { + return context.WithValue(ctx, alerting.ContextBasicAuth, alerting.BasicAuth{ + UserName: a.kibanaConfig.Username, + Password: a.kibanaConfig.Password, + }) + } } func (a *ApiClient) ID(ctx context.Context, resourceId string) (*CompositeId, diag.Diagnostics) { @@ -331,6 +347,7 @@ func buildKibanaClient(cfg config.Client) (*kibana.Client, error) { } kib, err := kibana.NewClient(*cfg.Kibana) + if err != nil { return nil, err } @@ -356,9 +373,23 @@ func buildAlertingClient(cfg config.Client) *alerting.APIClient { } func buildConnectorsClient(cfg config.Client) (*connectors.Client, error) { - basicAuthProvider, err := securityprovider.NewSecurityProviderBasicAuth(cfg.Kibana.Username, cfg.Kibana.Password) - if err != nil { - return nil, fmt.Errorf("unable to create basic auth provider: %w", err) + var authInterceptor connectors.ClientOption + if cfg.Kibana.ApiKey != "" { + apiKeyProvider, err := securityprovider.NewSecurityProviderApiKey( + "header", + "Authorization", + "ApiKey "+cfg.Kibana.ApiKey, + ) + if err != nil { + return nil, fmt.Errorf("unable to create api key auth provider: %w", err) + } + authInterceptor = connectors.WithRequestEditorFn(apiKeyProvider.Intercept) + } else { + basicAuthProvider, err := securityprovider.NewSecurityProviderBasicAuth(cfg.Kibana.Username, cfg.Kibana.Password) + if err != nil { + return nil, fmt.Errorf("unable to create basic auth provider: %w", err) + } + authInterceptor = connectors.WithRequestEditorFn(basicAuthProvider.Intercept) } httpClient := &http.Client{} @@ -371,7 +402,7 @@ func buildConnectorsClient(cfg config.Client) (*connectors.Client, error) { return connectors.NewClient( cfg.Kibana.Address, - connectors.WithRequestEditorFn(basicAuthProvider.Intercept), + authInterceptor, connectors.WithHTTPClient(httpClient), ) } diff --git a/internal/clients/config/base.go b/internal/clients/config/base.go index 89e2f3b45..ced9ee3e8 100644 --- a/internal/clients/config/base.go +++ b/internal/clients/config/base.go @@ -72,6 +72,7 @@ func (b baseConfig) toKibanaConfig() kibanaConfig { return kibanaConfig{ Username: b.Username, Password: b.Password, + ApiKey: b.ApiKey, } } diff --git a/internal/clients/config/fleet_test.go b/internal/clients/config/fleet_test.go index decc53ff8..914801714 100644 --- a/internal/clients/config/fleet_test.go +++ b/internal/clients/config/fleet_test.go @@ -177,7 +177,7 @@ func Test_newFleetConfigFromFramework(t *testing.T) { }, }, { - name: "should use the provided config optios", + name: "should use the provided config options", args: func() args { kibanaCfg := kibanaConfig{ Address: "example.com/kibana", diff --git a/internal/clients/config/kibana.go b/internal/clients/config/kibana.go index b0f80c806..526082dad 100644 --- a/internal/clients/config/kibana.go +++ b/internal/clients/config/kibana.go @@ -34,6 +34,10 @@ func newKibanaConfigFromSDK(d *schema.ResourceData, base baseConfig) (kibanaConf config.Password = password.(string) } + if apiKey, ok := kibConfig["api_key"]; ok && apiKey != "" { + config.ApiKey = apiKey.(string) + } + if endpoints, ok := kibConfig["endpoints"]; ok && len(endpoints.([]interface{})) > 0 { // We're curently limited by the API to a single endpoint if endpoint := endpoints.([]interface{})[0]; endpoint != nil { @@ -60,6 +64,9 @@ func newKibanaConfigFromFramework(ctx context.Context, cfg ProviderConfiguration if kibConfig.Password.ValueString() != "" { config.Password = kibConfig.Password.ValueString() } + if kibConfig.ApiKey.ValueString() != "" { + config.ApiKey = kibConfig.ApiKey.ValueString() + } var endpoints []string diags := kibConfig.Endpoints.ElementsAs(ctx, &endpoints, true) if diags.HasError() { @@ -79,6 +86,7 @@ func newKibanaConfigFromFramework(ctx context.Context, cfg ProviderConfiguration func (k kibanaConfig) withEnvironmentOverrides() kibanaConfig { k.Username = withEnvironmentOverride(k.Username, "KIBANA_USERNAME") k.Password = withEnvironmentOverride(k.Password, "KIBANA_PASSWORD") + k.ApiKey = withEnvironmentOverride(k.ApiKey, "KIBANA_API_KEY") k.Address = withEnvironmentOverride(k.Address, "KIBANA_ENDPOINT") if insecure, ok := os.LookupEnv("KIBANA_INSECURE"); ok { @@ -95,6 +103,7 @@ func (k kibanaConfig) toFleetConfig() fleetConfig { URL: k.Address, Username: k.Username, Password: k.Password, + APIKey: k.ApiKey, Insecure: k.DisableVerifySSL, } } diff --git a/internal/clients/config/kibana_test.go b/internal/clients/config/kibana_test.go index a7b8fbbac..5a5b68f99 100644 --- a/internal/clients/config/kibana_test.go +++ b/internal/clients/config/kibana_test.go @@ -42,7 +42,7 @@ func Test_newKibanaConfigFromSDK(t *testing.T) { }, }, { - name: "should use the provided config optios", + name: "should use the provided config options", args: func() args { baseCfg := baseConfig{ Username: "elastic", @@ -113,6 +113,7 @@ func Test_newKibanaConfigFromSDK(t *testing.T) { os.Unsetenv("KIBANA_PASSWORD") os.Unsetenv("KIBANA_ENDPOINT") os.Unsetenv("KIBANA_INSECURE") + os.Unsetenv("KIBANA_API_KEY") args := tt.args() rd := schema.TestResourceDataRaw(t, map[string]*schema.Schema{ @@ -159,7 +160,7 @@ func Test_newKibanaConfigFromFramework(t *testing.T) { }, }, { - name: "should use the provided config optios", + name: "should use the provided config options", args: func() args { baseCfg := baseConfig{ Username: "elastic", @@ -189,6 +190,34 @@ func Test_newKibanaConfigFromFramework(t *testing.T) { } }, }, + { + name: "should use api_key when provided in config options", + args: func() args { + baseCfg := baseConfig{ + ApiKey: "test", + } + + return args{ + baseCfg: baseCfg, + providerConfig: ProviderConfiguration{ + Kibana: []KibanaConnection{ + { + ApiKey: types.StringValue("test"), + Endpoints: types.ListValueMust(types.StringType, []attr.Value{ + types.StringValue("example.com/kibana"), + }), + Insecure: types.BoolValue(true), + }, + }, + }, + expectedConfig: kibanaConfig{ + Address: "example.com/kibana", + ApiKey: "test", + DisableVerifySSL: true, + }, + } + }, + }, { name: "should prefer environment variables", args: func() args { @@ -232,6 +261,7 @@ func Test_newKibanaConfigFromFramework(t *testing.T) { t.Run(tt.name, func(t *testing.T) { os.Unsetenv("KIBANA_USERNAME") os.Unsetenv("KIBANA_PASSWORD") + os.Unsetenv("KIBANA_API_KEY") os.Unsetenv("KIBANA_ENDPOINT") os.Unsetenv("KIBANA_INSECURE") diff --git a/internal/clients/config/provider.go b/internal/clients/config/provider.go index 7da987528..b089b8493 100644 --- a/internal/clients/config/provider.go +++ b/internal/clients/config/provider.go @@ -25,6 +25,7 @@ type ElasticsearchConnection struct { type KibanaConnection struct { Username types.String `tfsdk:"username"` Password types.String `tfsdk:"password"` + ApiKey types.String `tfsdk:"api_key"` Endpoints types.List `tfsdk:"endpoints"` Insecure types.Bool `tfsdk:"insecure"` } diff --git a/internal/kibana/alerting_test.go b/internal/kibana/alerting_test.go index e225ab39c..65f4016af 100644 --- a/internal/kibana/alerting_test.go +++ b/internal/kibana/alerting_test.go @@ -18,6 +18,8 @@ import ( func TestAccResourceAlertingRule(t *testing.T) { minSupportedVersion := version.Must(version.NewSemver("7.14.0")) + t.Setenv("KIBANA_API_KEY", "") + ruleName := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum) resource.Test(t, resource.TestCase{ diff --git a/internal/schema/connection.go b/internal/schema/connection.go index c77e1a2c8..5810aac46 100644 --- a/internal/schema/connection.go +++ b/internal/schema/connection.go @@ -119,6 +119,14 @@ func GetKbFWConnectionBlock() fwschema.Block { MarkdownDescription: "Kibana connection configuration block.", NestedObject: fwschema.NestedBlockObject{ Attributes: map[string]fwschema.Attribute{ + "api_key": fwschema.StringAttribute{ + MarkdownDescription: "API Key to use for authentication to Kibana", + Optional: true, + Sensitive: true, + Validators: []validator.String{ + stringvalidator.ConflictsWith(usernamePath, passwordPath), + }, + }, "username": fwschema.StringAttribute{ MarkdownDescription: "Username to use for API authentication to Kibana.", Optional: true, @@ -314,6 +322,7 @@ func GetEsConnectionSchema(keyName string, isProviderConfiguration bool) *schema } func GetKibanaConnectionSchema() *schema.Schema { + withEnvDefault := func(key string, dv interface{}) schema.SchemaDefaultFunc { return nil } return &schema.Schema{ Description: "Kibana connection configuration block.", Type: schema.TypeList, @@ -321,6 +330,14 @@ func GetKibanaConnectionSchema() *schema.Schema { Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "api_key": { + Description: "API Key to use for authentication to Kibana", + Type: schema.TypeString, + Optional: true, + Sensitive: true, + DefaultFunc: withEnvDefault("KIBANA_API_KEY", nil), + ConflictsWith: []string{"kibana.0.password", "kibana.0.username"}, + }, "username": { Description: "Username to use for API authentication to Kibana.", Type: schema.TypeString, diff --git a/libs/go-kibana-rest/.github/workflows/workflow.yml b/libs/go-kibana-rest/.github/workflows/workflow.yml new file mode 100644 index 000000000..cc918ffdb --- /dev/null +++ b/libs/go-kibana-rest/.github/workflows/workflow.yml @@ -0,0 +1,51 @@ +name: "build" + +on: + push: + branches: + - main + - 7.x + - 8.x + tags: + - "*" + pull_request: + branches: + - main + - 7.x + - 8.x + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Go + uses: actions/setup-go@v2 + with: + go-version: "1.19" + - name: Setup Elasticsearch / Kibana + run: | + set -e + docker-compose up elasticsearch & + echo "Waiting for Elasticsearch availability" + until curl -s http://localhost:9200 | grep -q 'missing authentication credentials'; do sleep 30; done; + echo "Setting kibana_system password" + until curl -s -X POST -u elastic:changeme -H "Content-Type: application/json" http://localhost:9200/_security/user/kibana_system/_password -d "{\"password\":\"changeme\"}" | grep -q "^{}"; do sleep 10; done + curl -XPOST -u elastic:changeme http://localhost:9200/_license/start_trial?acknowledge=true + docker-compose up kibana & + until $(curl --output /dev/null --silent --head --fail -u elastic:changeme http://localhost:5601); do sleep 5; done + sleep 10 + - name: golangci-lint + uses: golangci/golangci-lint-action@v3 + with: + version: latest + args: --timeout 600s + - name: Run build + run: go build + - name: Run test + run: make test + - uses: codecov/codecov-action@v2 + with: + files: coverage.out + flags: unittests + fail_ci_if_error: true \ No newline at end of file diff --git a/libs/go-kibana-rest/.gitignore b/libs/go-kibana-rest/.gitignore new file mode 100644 index 000000000..f1c181ec9 --- /dev/null +++ b/libs/go-kibana-rest/.gitignore @@ -0,0 +1,12 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out diff --git a/libs/go-kibana-rest/.theia/launch.json b/libs/go-kibana-rest/.theia/launch.json new file mode 100644 index 000000000..ee6285c12 --- /dev/null +++ b/libs/go-kibana-rest/.theia/launch.json @@ -0,0 +1,12 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug current file", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${fileDirname}" + } +] +} diff --git a/libs/go-kibana-rest/LICENSE b/libs/go-kibana-rest/LICENSE new file mode 100644 index 000000000..d56aa8ec4 --- /dev/null +++ b/libs/go-kibana-rest/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 disaster37 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/libs/go-kibana-rest/Makefile b/libs/go-kibana-rest/Makefile new file mode 100644 index 000000000..0091d2468 --- /dev/null +++ b/libs/go-kibana-rest/Makefile @@ -0,0 +1,18 @@ +TEST?=./... +PKG_NAME=kbapi +KIBANA_URL ?= http://127.0.0.1:5601 +KIBANA_USERNAME ?= elastic +KIBANA_PASSWORD ?= changeme + +all: help + + +test: fmt + KIBANA_URL=${KIBANA_URL} KIBANA_USERNAME=${KIBANA_USERNAME} KIBANA_PASSWORD=${KIBANA_PASSWORD} go test $(TEST) -v -count 1 -parallel 1 -race -coverprofile=coverage.out -covermode=atomic $(TESTARGS) -timeout 120m + +fmt: + @echo "==> Fixing source code with gofmt..." + gofmt -s -w ./ + + + diff --git a/libs/go-kibana-rest/README.md b/libs/go-kibana-rest/README.md new file mode 100644 index 000000000..c0c276bef --- /dev/null +++ b/libs/go-kibana-rest/README.md @@ -0,0 +1,337 @@ +# go-kibana-rest + +[![CircleCI](https://circleci.com/gh/disaster37/go-kibana-rest.svg?style=svg)](https://circleci.com/gh/disaster37/go-kibana-rest) +[![Go Report Card](https://goreportcard.com/badge/github.com/disaster37/go-kibana-rest)](https://goreportcard.com/report/github.com/disaster37/go-kibana-rest) +[![GoDoc](https://godoc.org/github.com/disaster37/go-kibana-rest?status.svg)](http://godoc.org/github.com/disaster37/go-kibana-rest) +[![codecov](https://codecov.io/gh/disaster37/go-kibana-rest/branch/master/graph/badge.svg)](https://codecov.io/gh/disaster37/go-kibana-rest) + +Go framework to handle kibana API + +## Compatibility + +It work with Kibana 7.x. and 8.x + +## Installation + +In your go.mod, put: +```go +require github.com/disaster37/go-kibana-rest/v8 +``` + +## Usage + +### Init the client + +```go +cfg := kibana.Config{ + Address: "http://127.0.0.1:5601", + Username: "elastic", + Password: "changeme", + DisableVerifySSL: true, +} + +client, err := kibana.NewClient(cfg) + +if err != nil { + log.Fatalf("Error creating the client: %s", err) +} + +status, err := client.API.KibanaStatus.Get() +if err != nil { + log.Fatalf("Error getting response: %s", err) +} +log.Println(status) +``` + +### Handle shorten URL + +```go +// Shorten long URL +shortenURL := &kbapi.ShortenURL{ + URL: "/app/kibana#/dashboard?_g=()&_a=(description:'',filters:!(),fullScreenMode:!f,options:(hidePanelTitles:!f,useMargins:!t),panels:!((embeddableConfig:(),gridData:(h:15,i:'1',w:24,x:0,y:0),id:'8f4d0c00-4c86-11e8-b3d7-01146121b73d',panelIndex:'1',type:visualization,version:'7.0.0-alpha1')),query:(language:lucene,query:''),timeRestore:!f,title:'New%20Dashboard',viewMode:edit)", +} +shortenURLResponse, err := client.API.KibanaShortenURL.Create(shortenURL) +if err != nil { + log.Fatalf("Error creating shorten URL: %s", err) +} +log.Println(fmt.Sprintf("http://localhost:5601/goto/%s", shortenURLResponse.ID)) +``` + +### Handle logstash Pipeline +```go +// Create or update Logstash pipeline +logstashPipeline := &kbapi.LogstashPipeline{ + ID: "sample", + Description: "Sample logstash pipeline", + Pipeline: "input { stdin {} } output { stdout {} }", + Settings: map[string]interface{}{ + "queue.type": "persisted", + }, +} +logstashPipeline, err = client.API.KibanaLogstashPipeline.CreateOrUpdate(logstashPipeline) +if err != nil { + log.Fatalf("Error creating logstash pipeline: %s", err) +} +log.Println(logstashPipeline) + +// Get the logstash pipeline +logstashPipeline, err = client.API.KibanaLogstashPipeline.Get("sample") +if err != nil { + log.Fatalf("Error getting logstash pipeline: %s", err) +} +log.Println(logstashPipeline) + +// Get all logstash pipeline +logstashPipelines, err := client.API.KibanaLogstashPipeline.List() +if err != nil { + log.Fatalf("Error getting all logstash pipeline: %s", err) +} +log.Println(logstashPipelines) + +// Delete logstash pipeline +err = client.API.KibanaLogstashPipeline.Delete("sample") +if err != nil { + log.Fatalf("Error deleting logstash pipeline: %s", err) +} +log.Println("Logstash pipeline 'sample' successfully deleted") +``` + +### Handle user space + +```go +// Create user space +space := &kbapi.KibanaSpace{ + ID: "test", + Name: "test", + Description: "My test", +} +space, err = client.API.KibanaSpaces.Create(space) +if err != nil { + log.Fatalf("Error creating user space: %s", err) +} +log.Println(space) + +// Update user space +space.Name = "new name" +space, err = client.API.KibanaSpaces.Update(space) +if err != nil { + log.Fatalf("Error updating user space: %s", err) +} +log.Println(space) + +// Get the user space +space, err = client.API.KibanaSpaces.Get("test") +if err != nil { + log.Fatalf("Error getting user space: %s", err) +} +log.Println(space) + +// Get all user space +spaces, err := client.API.KibanaSpaces.List() +if err != nil { + log.Fatalf("Error getting all user spaces: %s", err) +} +log.Println(spaces) + +// Copy config object from default space to test space +parameter := &kbapi.KibanaSpaceCopySavedObjectParameter{ + Spaces: []string{"test"}, + IncludeReferences: true, + Overwrite: true, + Objects: []kbapi.KibanaSpaceObjectParameter{ + { + Type: "config", + ID: "7.4.2", + }, + }, +} +err = client.API.KibanaSpaces.CopySavedObjects(parameter, "") +if err != nil { + log.Fatalf("Error copying object from another user space: %s", err) +} +log.Println("Copying config object from 'default' to 'test' user space successfully") + + +// Delete user space +err = client.API.KibanaSpaces.Delete("test") +if err != nil { + log.Fatalf("Error deleteing user space: %s", err) +} +log.Println("User space 'test' successfully deleted") +``` + +### Handle dashboard + +```go +// Import dashboard from file in default user space +b, err := ioutil.ReadFile("../fixtures/kibana-dashboard.json") +if err != nil { + log.Fatalf("Error reading file: %s", err) +} +data := make(map[string]interface{}) +err = json.Unmarshal(b, &data) +err = client.API.KibanaDashboard.Import(data, nil, true, "default") +if err != nil { + log.Fatalf("Error importing dashboard: %s", err) +} +log.Println("Importing dashboard successfully") + +// Export dashboard from default user space +data, err = client.API.KibanaDashboard.Export([]string{"edf84fe0-e1a0-11e7-b6d5-4dc382ef7f5b"}, "default") +if err != nil { + log.Fatalf("Error exporting dashboard: %s", err) +} +log.Println("Exporting dashboard successfully: %s", data) +``` + +### Handle role management + +```go +// Create or update role +role := &kbapi.KibanaRole{ + Name: "test", + Elasticsearch: &kbapi.KibanaRoleElasticsearch{ + Indices: []kbapi.KibanaRoleElasticsearchIndice{ + { + Names: []string{ + "*", + }, + Privileges: []string{ + "read", + }, + }, + }, + }, + Kibana: []kbapi.KibanaRoleKibana{ + { + Base: []string{ + "read", + }, + }, + }, +} +role, err = client.API.KibanaRoleManagement.CreateOrUpdate(role) +if err != nil { + log.Fatalf("Error creating role: %s", role) +} +log.Println(role) + +// Get the role +role, err = client.API.KibanaRoleManagement.Get("test") +if err != nil { + log.Fatalf("Error reading role: %s", role) +} +log.Println(role) + +// List all roles +roles, err := client.API.KibanaRoleManagement.List() +if err != nil { + log.Fatalf("Error reading all roles: %s", err) +} +log.Println(roles) + +// Delete role +err = client.API.KibanaRoleManagement.Delete("test") +if err != nil { + log.Fatalf("Error deleting role: %s", err) +} +log.Println("Role successfully deleted") +``` + +### Handle save object + +```go +// Create new index pattern in default user space +dataJSON := `{"attributes": {"title": "test-pattern-*"}}` +data = make(map[string]interface{}) +err = json.Unmarshal([]byte(dataJSON), &data) +if err != nil { + log.Fatalf("Error converting json to struct: %s", err) +} +resp, err := client.API.KibanaSavedObject.Create(data, "index-pattern", "test", true, "default") +if err != nil { + log.Fatalf("Error creating object: %s", err) +} +log.Println(resp) + +// Get index pattern save object from default user space +resp, err = client.API.KibanaSavedObject.Get("index-pattern", "test", "default") +if err != nil { + log.Fatalf("Error getting index pattern save object: %s", err) +} +log.Println(resp) + +// Search index pattern from default user space +parameters := &kbapi.OptionalFindParameters{ + Search: "test", + SearchFields: []string{"id"}, + Fields: []string{"id"}, +} +resp, err = client.API.KibanaSavedObject.Find("index-pattern", "default", parameters) +if err != nil { + log.Fatalf("Error searching index pattern: %s", err) +} +log.Println(resp) + +// Update index pattern in default user space +dataJSON = `{"attributes": {"title": "test-pattern2-*"}}` +err = json.Unmarshal([]byte(dataJSON), &data) +if err != nil { + log.Fatalf("Error converting json to struct") +} +resp, err = client.API.KibanaSavedObject.Update(data, "index-pattern", "test", "default") +if err != nil { + log.Fatalf("Error updating index pattern: %s", err) +} + +// Export index pattern from default user space +request := []map[string]string{ + { + "type": "index-pattern", + "id": "test", + }, +} +resp, err = client.API.KibanaSavedObject.Export(nil, request, true, "default") +if err != nil { + log.Fatalf("Error exporting index pattern: %s", err) +} +log.Println(resp) + +// import index pattern in default user space +b, err = json.Marshal(resp) +if err != nil { + log.Fatalf("Error converting struct to json") +} +resp2, err := client.API.KibanaSavedObject.Import(b, true, "default") +if err != nil { + log.Fatalf("Error importing index pattern: %s", err) +} +log.Println(resp2) + +// Delete index pattern in default user space +err = client.API.KibanaSavedObject.Delete("index-pattern", "test", "default") +if err != nil { + log.Fatalf("Error deleting index pattern: %s", err) +} +log.Println("Index pattern successfully deleted") +``` + +### Handle status + +```go +status, err := client.API.KibanaStatus.Get() +if err != nil { + log.Fatalf("Error getting status: %s", err) +} +log.Println(status) +``` + +## Contribute + +First, if you use kibana module that required license like Logstash Pipeline, you need to have valid license or start trial license. + +Start trial license: +```bash +curl -XPOST -u elastic:changeme "http://localhost:9200/_license/start_trial?acknowledge=true&pretty" + +``` \ No newline at end of file diff --git a/libs/go-kibana-rest/_examples/sample.go b/libs/go-kibana-rest/_examples/sample.go new file mode 100644 index 000000000..053a8513a --- /dev/null +++ b/libs/go-kibana-rest/_examples/sample.go @@ -0,0 +1,283 @@ +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + + "github.com/disaster37/go-kibana-rest/v8" + "github.com/disaster37/go-kibana-rest/v8/kbapi" +) + +func main() { + + cfg := kibana.Config{ + Address: "http://127.0.0.1:5601", + Username: "elastic", + Password: "changeme", + DisableVerifySSL: true, + } + + client, err := kibana.NewClient(cfg) + + if err != nil { + log.Fatalf("Error creating the client: %s", err) + } + + status, err := client.API.KibanaStatus.Get() + if err != nil { + log.Fatalf("Error getting response: %s", err) + } + log.Println(status) + + // Shorten long URL + shortenURL := &kbapi.ShortenURL{ + URL: "/app/kibana#/dashboard?_g=()&_a=(description:'',filters:!(),fullScreenMode:!f,options:(hidePanelTitles:!f,useMargins:!t),panels:!((embeddableConfig:(),gridData:(h:15,i:'1',w:24,x:0,y:0),id:'8f4d0c00-4c86-11e8-b3d7-01146121b73d',panelIndex:'1',type:visualization,version:'7.0.0-alpha1')),query:(language:lucene,query:''),timeRestore:!f,title:'New%20Dashboard',viewMode:edit)", + } + shortenURLResponse, err := client.API.KibanaShortenURL.Create(shortenURL) + if err != nil { + log.Fatalf("Error creating shorten URL: %s", err) + } + log.Println(fmt.Sprintf("http://localhost:5601/goto/%s", shortenURLResponse.ID)) + + // Create or update Logstash pipeline + logstashPipeline := &kbapi.LogstashPipeline{ + ID: "sample", + Description: "Sample logstash pipeline", + Pipeline: "input { stdin {} } output { stdout {} }", + Settings: map[string]interface{}{ + "queue.type": "persisted", + }, + } + logstashPipeline, err = client.API.KibanaLogstashPipeline.CreateOrUpdate(logstashPipeline) + if err != nil { + log.Fatalf("Error creating logstash pipeline: %s", err) + } + log.Println(logstashPipeline) + + // Get the logstash pipeline + logstashPipeline, err = client.API.KibanaLogstashPipeline.Get("sample") + if err != nil { + log.Fatalf("Error getting logstash pipeline: %s", err) + } + log.Println(logstashPipeline) + + // Get all logstash pipeline + logstashPipelines, err := client.API.KibanaLogstashPipeline.List() + if err != nil { + log.Fatalf("Error getting all logstash pipeline: %s", err) + } + log.Println(logstashPipelines) + + // Delete logstash pipeline + err = client.API.KibanaLogstashPipeline.Delete("sample") + if err != nil { + log.Fatalf("Error deleting logstash pipeline: %s", err) + } + log.Println("Logstash pipeline 'sample' successfully deleted") + + // Create user space + space := &kbapi.KibanaSpace{ + ID: "test", + Name: "test", + Description: "My test", + } + space, err = client.API.KibanaSpaces.Create(space) + if err != nil { + log.Fatalf("Error creating user space: %s", err) + } + log.Println(space) + + // Update user space + space.Name = "new name" + space, err = client.API.KibanaSpaces.Update(space) + if err != nil { + log.Fatalf("Error updating user space: %s", err) + } + log.Println(space) + + // Get the user space + space, err = client.API.KibanaSpaces.Get("test") + if err != nil { + log.Fatalf("Error getting user space: %s", err) + } + log.Println(space) + + // Get all user space + spaces, err := client.API.KibanaSpaces.List() + if err != nil { + log.Fatalf("Error getting all user spaces: %s", err) + } + log.Println(spaces) + + // Copy config object from default space to test space + parameter := &kbapi.KibanaSpaceCopySavedObjectParameter{ + Spaces: []string{"test"}, + IncludeReferences: true, + Overwrite: true, + Objects: []kbapi.KibanaSpaceObjectParameter{ + { + Type: "config", + ID: "7.4.2", + }, + }, + } + err = client.API.KibanaSpaces.CopySavedObjects(parameter, "") + if err != nil { + log.Fatalf("Error copying object from another user space: %s", err) + } + log.Println("Copying config object from 'default' to 'test' user space successfully") + + // Delete user space + err = client.API.KibanaSpaces.Delete("test") + if err != nil { + log.Fatalf("Error deleteing user space: %s", err) + } + log.Println("User space 'test' successfully deleted") + + // Import dashboard from file in default user space + b, err := ioutil.ReadFile("../fixtures/kibana-dashboard.json") + if err != nil { + log.Fatalf("Error reading file: %s", err) + } + data := make(map[string]interface{}) + err = json.Unmarshal(b, &data) + err = client.API.KibanaDashboard.Import(data, nil, true, "default") + if err != nil { + log.Fatalf("Error importing dashboard: %s", err) + } + log.Println("Importing dashboard successfully") + + // Export dashboard from default user space + data, err = client.API.KibanaDashboard.Export([]string{"edf84fe0-e1a0-11e7-b6d5-4dc382ef7f5b"}, "default") + if err != nil { + log.Fatalf("Error exporting dashboard: %s", err) + } + log.Println(data) + + // Create or update role + role := &kbapi.KibanaRole{ + Name: "test", + Elasticsearch: &kbapi.KibanaRoleElasticsearch{ + Indices: []kbapi.KibanaRoleElasticsearchIndice{ + { + Names: []string{ + "*", + }, + Privileges: []string{ + "read", + }, + }, + }, + }, + Kibana: []kbapi.KibanaRoleKibana{ + { + Base: []string{ + "read", + }, + }, + }, + } + role, err = client.API.KibanaRoleManagement.CreateOrUpdate(role) + if err != nil { + log.Fatalf("Error creating role: %s", role) + } + log.Println(role) + + // Get the role + role, err = client.API.KibanaRoleManagement.Get("test") + if err != nil { + log.Fatalf("Error reading role: %s", role) + } + log.Println(role) + + // List all roles + roles, err := client.API.KibanaRoleManagement.List() + if err != nil { + log.Fatalf("Error reading all roles: %s", err) + } + log.Println(roles) + + // Delete role + err = client.API.KibanaRoleManagement.Delete("test") + if err != nil { + log.Fatalf("Error deleting role: %s", err) + } + log.Println("Role successfully deleted") + + // Create new index pattern in default user space + dataJSON := `{"attributes": {"title": "test-pattern-*"}}` + data = make(map[string]interface{}) + err = json.Unmarshal([]byte(dataJSON), &data) + if err != nil { + log.Fatalf("Error converting json to struct: %s", err) + } + resp, err := client.API.KibanaSavedObject.Create(data, "index-pattern", "test", true, "default") + if err != nil { + log.Fatalf("Error creating object: %s", err) + } + log.Println(resp) + + // Get index pattern save object from default user space + resp, err = client.API.KibanaSavedObject.Get("index-pattern", "test", "default") + if err != nil { + log.Fatalf("Error getting index pattern save object: %s", err) + } + log.Println(resp) + + // Search index pattern from default user space + parameters := &kbapi.OptionalFindParameters{ + Search: "test", + SearchFields: []string{"id"}, + Fields: []string{"id"}, + } + resp, err = client.API.KibanaSavedObject.Find("index-pattern", "default", parameters) + if err != nil { + log.Fatalf("Error searching index pattern: %s", err) + } + log.Println(resp) + + // Update index pattern in default user space + dataJSON = `{"attributes": {"title": "test-pattern2-*"}}` + err = json.Unmarshal([]byte(dataJSON), &data) + if err != nil { + log.Fatalf("Error converting json to struct") + } + resp, err = client.API.KibanaSavedObject.Update(data, "index-pattern", "test", "default") + if err != nil { + log.Fatalf("Error updating index pattern: %s", err) + } + + // Export index pattern from default user space + request := []map[string]string{ + { + "type": "index-pattern", + "id": "test", + }, + } + response, error := client.API.KibanaSavedObject.Export(nil, request, true, "default") + if error != nil { + log.Fatalf("Error exporting index pattern: %s", error) + } + log.Println(response) + + // import index pattern in default user space + b, err = json.Marshal(response) + if err != nil { + log.Fatalf("Error converting struct to json") + } + resp2, err := client.API.KibanaSavedObject.Import(b, true, "default") + if err != nil { + log.Fatalf("Error importing index pattern: %s", err) + } + log.Println(resp2) + + // Delete index pattern in default user space + err = client.API.KibanaSavedObject.Delete("index-pattern", "test", "default") + if err != nil { + log.Fatalf("Error deleting index pattern: %s", err) + } + log.Println("Index pattern successfully deleted") + +} diff --git a/libs/go-kibana-rest/coverage.txt b/libs/go-kibana-rest/coverage.txt new file mode 100644 index 000000000..5b61039f0 --- /dev/null +++ b/libs/go-kibana-rest/coverage.txt @@ -0,0 +1,354 @@ +mode: atomic +github.com/disaster37/go-kibana-rest/v7/kibana.go:26.42,28.2 1 1 +github.com/disaster37/go-kibana-rest/v7/kibana.go:31.45,32.23 1 2 +github.com/disaster37/go-kibana-rest/v7/kibana.go:36.2,42.31 2 2 +github.com/disaster37/go-kibana-rest/v7/kibana.go:46.2,51.34 2 2 +github.com/disaster37/go-kibana-rest/v7/kibana.go:55.2,55.20 1 2 +github.com/disaster37/go-kibana-rest/v7/kibana.go:32.23,34.3 1 1 +github.com/disaster37/go-kibana-rest/v7/kibana.go:42.31,44.3 1 0 +github.com/disaster37/go-kibana-rest/v7/kibana.go:51.34,53.3 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api._.go:72.32,114.2 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:67.38,70.2 2 4 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:73.78,74.48 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:74.48,76.17 1 3 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:79.3,83.17 4 3 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:86.3,87.31 2 3 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:93.3,95.17 3 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:98.3,100.25 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:76.17,78.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:83.17,85.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:87.31,88.32 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:91.4,91.61 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:88.32,90.5 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:95.17,97.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:106.80,107.37 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:107.37,110.17 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:113.3,114.31 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:117.3,119.17 3 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:122.3,124.26 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:110.17,112.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:114.31,116.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:119.17,121.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:130.100,131.59 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:131.59,133.24 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:136.3,143.17 7 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:146.3,147.17 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:150.3,151.31 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:156.3,157.17 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:161.3,163.25 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:133.24,135.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:143.17,145.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:147.17,149.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:151.31,153.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:157.17,159.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:169.84,170.33 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:170.33,172.17 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:175.3,179.17 4 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:182.3,183.31 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:187.3,187.13 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:172.17,174.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:179.17,181.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_role_management.go:183.31,185.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_status.go:21.62,22.38 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_status.go:22.38,24.17 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_status.go:27.3,28.31 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_status.go:34.3,36.17 3 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_status.go:39.3,41.27 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_status.go:24.17,26.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_status.go:28.31,29.32 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_status.go:32.4,32.61 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_status.go:29.32,31.5 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_status.go:36.17,38.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:22.74,23.83 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:23.83,25.23 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:28.3,32.52 4 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:38.3,42.17 4 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:45.3,46.31 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:53.3,55.17 3 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:58.3,60.19 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:25.23,27.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:32.52,34.4 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:34.9,36.4 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:42.17,44.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:46.31,47.32 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:50.4,50.61 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:47.32,49.5 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:55.17,57.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:66.74,67.107 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:67.107,69.18 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:72.3,78.52 6 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:84.3,87.31 3 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:90.3,91.17 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:94.3,95.17 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:98.3,99.31 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:102.3,104.17 3 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:107.3,111.13 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:69.18,71.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:78.52,80.4 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:80.9,82.4 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:87.31,89.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:91.17,93.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:95.17,97.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:99.31,101.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_dashboard.go:104.17,106.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:45.44,48.2 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:51.82,52.52 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:52.52,54.15 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:57.3,61.17 4 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:64.3,65.31 2 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:71.3,73.17 3 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:76.3,78.31 2 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:54.15,56.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:61.17,63.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:65.31,66.32 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:69.4,69.61 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:66.32,68.5 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:73.17,75.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:83.84,84.43 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:84.43,88.17 3 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:91.3,92.31 2 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:95.3,97.17 3 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:100.3,102.46 2 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:88.17,90.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:92.31,94.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:97.17,99.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:108.104,109.77 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:109.77,111.30 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:115.3,118.17 3 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:122.3,124.17 3 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:128.3,129.31 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:134.3,135.17 2 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:138.3,138.30 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:142.3,144.31 2 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:111.30,113.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:118.17,120.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:124.17,126.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:129.31,131.4 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:135.17,137.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:138.30,140.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:149.88,150.31 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:150.31,152.15 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:155.3,159.17 4 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:162.3,163.31 2 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:167.3,167.13 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:152.15,154.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:159.17,161.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_logstash_pipeline.go:163.31,165.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:52.50,55.2 2 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:58.72,59.96 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:59.96,61.23 1 4 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:64.3,64.15 1 4 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:67.3,72.52 5 4 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:77.3,80.17 3 4 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:83.3,84.31 2 4 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:91.3,93.17 3 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:96.3,98.19 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:61.23,63.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:64.15,66.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:72.52,74.4 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:74.9,76.4 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:80.17,82.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:84.31,85.32 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:88.4,88.61 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:85.32,87.5 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:93.17,95.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:104.74,105.129 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:105.129,107.23 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:110.3,116.32 4 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:151.3,152.52 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:157.3,160.17 3 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:163.3,164.31 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:171.3,173.17 3 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:176.3,178.19 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:107.23,109.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:116.32,125.46 9 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:128.4,128.36 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:131.4,131.39 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:134.4,134.54 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:137.4,137.46 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:140.4,140.40 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:143.4,143.42 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:146.4,146.45 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:125.46,127.5 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:128.36,130.5 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:131.39,133.5 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:134.54,136.5 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:137.46,139.5 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:140.40,142.5 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:143.42,145.5 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:146.45,148.5 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:152.52,154.4 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:154.9,156.4 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:160.17,162.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:164.31,165.32 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:168.4,168.61 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:165.32,167.5 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:173.17,175.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:184.78,185.141 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:185.141,187.18 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:190.3,190.23 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:193.3,200.52 7 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:205.3,208.17 3 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:211.3,212.17 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:215.3,216.31 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:219.3,221.17 3 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:224.3,226.27 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:187.18,189.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:190.23,192.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:200.52,202.4 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:202.9,204.4 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:208.17,210.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:212.17,214.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:216.31,218.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:221.17,223.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:231.78,232.125 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:232.125,234.18 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:237.3,237.23 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:240.3,240.15 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:243.3,249.52 6 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:254.3,257.17 3 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:260.3,261.17 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:264.3,265.31 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:268.3,270.17 3 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:273.3,275.27 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:234.18,236.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:237.23,239.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:240.15,242.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:249.52,251.4 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:251.9,253.4 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:257.17,259.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:261.17,263.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:265.31,267.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:270.17,272.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:280.78,281.70 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:281.70,283.23 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:286.3,286.15 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:289.3,294.52 5 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:299.3,302.17 3 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:305.3,306.31 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:309.3,311.17 3 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:314.3,316.13 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:283.23,285.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:286.15,288.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:294.52,296.4 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:296.9,298.4 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:302.17,304.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:306.31,308.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:311.17,313.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:321.78,322.121 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:322.121,331.27 6 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:334.3,334.23 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:337.3,341.52 4 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:346.3,349.17 3 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:352.3,353.17 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:356.3,357.31 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:361.3,364.19 3 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:331.27,333.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:334.23,336.4 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:341.52,343.4 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:343.9,345.4 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:349.17,351.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:353.17,355.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:357.31,359.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:370.78,371.95 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:371.95,373.21 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:377.3,382.52 5 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:387.3,393.17 3 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:396.3,397.31 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:400.3,402.17 3 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:405.3,407.27 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:373.21,375.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:382.52,384.4 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:384.9,386.4 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:393.17,395.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:397.31,399.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_save_object.go:402.17,404.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_shorten_url.go:28.38,31.2 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_shorten_url.go:34.46,37.2 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_shorten_url.go:40.76,41.67 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_shorten_url.go:41.67,43.24 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_shorten_url.go:46.3,49.17 3 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_shorten_url.go:53.3,56.17 3 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_shorten_url.go:60.3,61.31 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_shorten_url.go:65.3,67.17 3 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_shorten_url.go:70.3,72.33 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_shorten_url.go:43.24,45.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_shorten_url.go:49.17,51.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_shorten_url.go:56.17,58.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_shorten_url.go:61.31,63.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_shorten_url.go:67.17,69.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:63.39,66.2 2 7 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:69.60,70.47 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:70.47,72.15 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:75.3,79.17 4 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:82.3,83.31 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:90.3,92.17 3 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:95.3,97.26 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:72.15,74.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:79.17,81.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:83.31,84.32 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:87.4,87.61 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:84.32,86.5 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:92.17,94.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:103.62,104.38 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:104.38,108.17 3 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:111.3,112.31 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:115.3,117.17 3 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:120.3,122.27 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:108.17,110.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:112.31,114.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:117.17,119.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:128.66,129.62 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:129.62,131.25 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:134.3,137.17 3 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:140.3,142.17 3 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:146.3,147.31 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:150.3,152.17 3 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:155.3,157.26 2 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:131.25,133.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:137.17,139.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:142.17,144.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:147.31,149.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:152.17,154.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:163.86,164.88 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:164.88,166.23 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:169.3,173.52 4 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:178.3,179.17 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:182.3,183.17 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:187.3,188.31 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:191.3,193.17 3 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:196.3,199.34 3 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:204.3,204.22 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:208.3,208.13 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:166.23,168.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:173.52,175.4 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:175.9,177.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:179.17,181.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:183.17,185.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:188.31,190.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:193.17,195.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:199.34,200.66 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:200.66,202.5 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:204.22,206.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:214.66,215.31 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:215.31,217.15 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:221.3,225.17 4 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:228.3,229.31 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:235.3,235.13 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:217.15,219.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:225.17,227.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:229.31,233.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:241.66,242.62 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:242.62,244.25 1 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:247.3,250.17 3 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:253.3,255.17 3 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:259.3,260.31 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:263.3,265.17 3 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:268.3,270.26 2 1 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:244.25,246.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:250.17,252.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:255.17,257.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:260.31,262.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/api.kibana_spaces.go:265.17,267.4 1 0 +github.com/disaster37/go-kibana-rest/v7/kbapi/error.go:14.34,16.2 1 2 +github.com/disaster37/go-kibana-rest/v7/kbapi/error.go:19.76,24.2 1 2 diff --git a/libs/go-kibana-rest/doc.go b/libs/go-kibana-rest/doc.go new file mode 100644 index 000000000..dd57b9f87 --- /dev/null +++ b/libs/go-kibana-rest/doc.go @@ -0,0 +1,4 @@ +/* +Package kibana provides a Go client for Kibana. +*/ +package kibana diff --git a/libs/go-kibana-rest/docker-compose.yml b/libs/go-kibana-rest/docker-compose.yml new file mode 100644 index 000000000..31aaa2449 --- /dev/null +++ b/libs/go-kibana-rest/docker-compose.yml @@ -0,0 +1,21 @@ +version: '2.3' +services: + elasticsearch: + image: docker.elastic.co/elasticsearch/elasticsearch:8.5.0 + environment: + cluster.name: test + discovery.type: single-node + ELASTIC_PASSWORD: changeme + xpack.security.enabled: "true" + ports: + - "9200:9200/tcp" + kibana: + image: docker.elastic.co/kibana/kibana:8.5.0 + environment: + ELASTICSEARCH_HOSTS: http://es:9200 + ELASTICSEARCH_USERNAME: kibana_system + ELASTICSEARCH_PASSWORD: changeme + links: + - elasticsearch:es + ports: + - "5601:5601/tcp" \ No newline at end of file diff --git a/libs/go-kibana-rest/fixtures/kibana-dashboard.json b/libs/go-kibana-rest/fixtures/kibana-dashboard.json new file mode 100644 index 000000000..0749a5253 --- /dev/null +++ b/libs/go-kibana-rest/fixtures/kibana-dashboard.json @@ -0,0 +1,371 @@ +{ + "version": "7.2.0", + "objects": [ + { + "id": "edf84fe0-e1a0-11e7-b6d5-4dc382ef7f5b", + "type": "dashboard", + "updated_at": "2019-07-08T15:35:44.395Z", + "version": "WzIxLDFd", + "attributes": { + "title": "[Logs] Web Traffic", + "hits": 0, + "description": "Analyze mock web traffic log data for Elastic's website", + "panelsJSON": "[{\"embeddableConfig\":{\"vis\":{\"colors\":{\"Avg. Bytes\":\"#6ED0E0\",\"Unique Visitors\":\"#0A437C\"},\"legendOpen\":false}},\"gridData\":{\"x\":27,\"y\":11,\"w\":21,\"h\":13,\"i\":\"2\"},\"panelIndex\":\"2\",\"version\":\"7.0.0-alpha1\",\"panelRefName\":\"panel_0\"},{\"gridData\":{\"x\":0,\"y\":49,\"w\":24,\"h\":18,\"i\":\"4\"},\"panelIndex\":\"4\",\"version\":\"7.0.0-alpha1\",\"panelRefName\":\"panel_1\"},{\"embeddableConfig\":{\"vis\":{\"defaultColors\":{\"0 - 22\":\"rgb(247,251,255)\",\"22 - 44\":\"rgb(208,225,242)\",\"44 - 66\":\"rgb(148,196,223)\",\"66 - 88\":\"rgb(74,152,201)\",\"88 - 110\":\"rgb(23,100,171)\"},\"legendOpen\":false}},\"gridData\":{\"x\":0,\"y\":36,\"w\":24,\"h\":13,\"i\":\"7\"},\"panelIndex\":\"7\",\"version\":\"6.3.0\",\"panelRefName\":\"panel_2\"},{\"embeddableConfig\":{\"mapCenter\":[36.8092847020594,-96.94335937500001],\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}},\"gridData\":{\"x\":27,\"y\":24,\"w\":21,\"h\":12,\"i\":\"9\"},\"panelIndex\":\"9\",\"version\":\"6.3.0\",\"panelRefName\":\"panel_3\"},{\"embeddableConfig\":{\"vis\":{\"colors\":{\"0 - 500\":\"#BF1B00\",\"1000 - 1500\":\"#7EB26D\",\"500 - 1000\":\"#F2C96D\"},\"defaultColors\":{\"0 - 500\":\"rgb(165,0,38)\",\"1000 - 1500\":\"rgb(0,104,55)\",\"500 - 1000\":\"rgb(255,255,190)\"},\"legendOpen\":false}},\"gridData\":{\"x\":10,\"y\":0,\"w\":9,\"h\":11,\"i\":\"11\"},\"panelIndex\":\"11\",\"title\":\"\",\"version\":\"6.3.0\",\"panelRefName\":\"panel_4\"},{\"gridData\":{\"x\":0,\"y\":24,\"w\":27,\"h\":12,\"i\":\"13\"},\"panelIndex\":\"13\",\"version\":\"6.3.0\",\"panelRefName\":\"panel_5\"},{\"gridData\":{\"x\":24,\"y\":36,\"w\":24,\"h\":31,\"i\":\"14\"},\"panelIndex\":\"14\",\"version\":\"6.3.0\",\"panelRefName\":\"panel_6\"},{\"gridData\":{\"x\":0,\"y\":11,\"w\":27,\"h\":13,\"i\":\"15\"},\"panelIndex\":\"15\",\"version\":\"6.3.0\",\"panelRefName\":\"panel_7\"},{\"gridData\":{\"x\":19,\"y\":0,\"w\":15,\"h\":11,\"i\":\"16\"},\"panelIndex\":\"16\",\"title\":\"\",\"version\":\"6.3.0\",\"panelRefName\":\"panel_8\"},{\"embeddableConfig\":{\"vis\":{\"legendOpen\":false}},\"gridData\":{\"x\":34,\"y\":0,\"w\":14,\"h\":11,\"i\":\"17\"},\"panelIndex\":\"17\",\"version\":\"6.3.0\",\"panelRefName\":\"panel_9\"},{\"embeddableConfig\":{},\"gridData\":{\"x\":0,\"y\":0,\"w\":10,\"h\":11,\"i\":\"18\"},\"panelIndex\":\"18\",\"title\":\"\",\"version\":\"7.0.0-alpha1\",\"panelRefName\":\"panel_10\"}]", + "optionsJSON": "{\"hidePanelTitles\":false,\"useMargins\":true}", + "version": 1, + "timeRestore": true, + "timeTo": "now", + "timeFrom": "now-7d", + "refreshInterval": { + "pause": false, + "value": 900000 + }, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[],\"highlightAll\":true,\"version\":true}" + } + }, + "references": [ + { + "name": "panel_0", + "type": "visualization", + "id": "e1d0f010-9ee7-11e7-8711-e7a007dcef99" + }, + { + "name": "panel_1", + "type": "visualization", + "id": "06cf9c40-9ee8-11e7-8711-e7a007dcef99" + }, + { + "name": "panel_2", + "type": "visualization", + "id": "935afa20-e0cd-11e7-9d07-1398ccfcefa3" + }, + { + "name": "panel_3", + "type": "visualization", + "id": "4eb6e500-e1c7-11e7-b6d5-4dc382ef7f5b" + }, + { + "name": "panel_4", + "type": "visualization", + "id": "69a34b00-9ee8-11e7-8711-e7a007dcef99" + }, + { + "name": "panel_5", + "type": "visualization", + "id": "42b997f0-0c26-11e8-b0ec-3bb475f6b6ff" + }, + { + "name": "panel_6", + "type": "visualization", + "id": "7cbd2350-2223-11e8-b802-5bcf64c2cfb4" + }, + { + "name": "panel_7", + "type": "visualization", + "id": "314c6f60-2224-11e8-b802-5bcf64c2cfb4" + }, + { + "name": "panel_8", + "type": "visualization", + "id": "24a3e970-4257-11e8-b3aa-73fdaf54bfc9" + }, + { + "name": "panel_9", + "type": "visualization", + "id": "14e2e710-4258-11e8-b3aa-73fdaf54bfc9" + }, + { + "name": "panel_10", + "type": "visualization", + "id": "47f2c680-a6e3-11e8-94b4-c30c0228351b" + } + ], + "migrationVersion": { + "dashboard": "7.0.0" + } + }, + { + "id": "e1d0f010-9ee7-11e7-8711-e7a007dcef99", + "type": "visualization", + "updated_at": "2019-07-08T15:35:44.395Z", + "version": "WzksMV0=", + "attributes": { + "title": "[Logs] Unique Visitors vs. Average Bytes", + "visState": "{\"title\":\"[Logs] Unique Visitors vs. Average Bytes\",\"type\":\"area\",\"params\":{\"type\":\"area\",\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"truncate\":100},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Avg. Bytes\"}},{\"id\":\"ValueAxis-2\",\"name\":\"RightAxis-1\",\"type\":\"value\",\"position\":\"right\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Unique Visitors\"}}],\"seriesParams\":[{\"show\":\"true\",\"type\":\"histogram\",\"mode\":\"stacked\",\"data\":{\"label\":\"Avg. Bytes\",\"id\":\"1\"},\"drawLinesBetweenPoints\":true,\"showCircles\":true,\"interpolate\":\"linear\",\"valueAxis\":\"ValueAxis-1\"},{\"show\":true,\"mode\":\"stacked\",\"type\":\"line\",\"drawLinesBetweenPoints\":false,\"showCircles\":true,\"interpolate\":\"linear\",\"data\":{\"id\":\"2\",\"label\":\"Unique Visitors\"},\"valueAxis\":\"ValueAxis-2\"}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false,\"radiusRatio\":17},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"avg\",\"schema\":\"metric\",\"params\":{\"field\":\"bytes\",\"customLabel\":\"Avg. Bytes\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"cardinality\",\"schema\":\"metric\",\"params\":{\"field\":\"clientip\",\"customLabel\":\"Unique Visitors\"}},{\"id\":\"3\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"timestamp\",\"interval\":\"auto\",\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"4\",\"enabled\":true,\"type\":\"count\",\"schema\":\"radius\",\"params\":{}}]}", + "uiStateJSON": "{\"vis\":{\"colors\":{\"Avg. Bytes\":\"#70DBED\",\"Unique Visitors\":\"#0A437C\"}}}", + "description": "", + "version": 1, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + } + }, + "references": [ + { + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern", + "id": "90943e30-9a47-11e8-b64d-95841ca0b247" + } + ], + "migrationVersion": { + "visualization": "7.2.0" + } + }, + { + "id": "06cf9c40-9ee8-11e7-8711-e7a007dcef99", + "type": "visualization", + "updated_at": "2019-07-08T15:35:44.395Z", + "version": "WzEwLDFd", + "attributes": { + "title": "[Logs] Unique Visitors by Country", + "visState": "{\"title\":\"[Logs] Unique Visitors by Country\",\"type\":\"region_map\",\"params\":{\"legendPosition\":\"bottomright\",\"addTooltip\":true,\"colorSchema\":\"Reds\",\"selectedLayer\":{\"attribution\":\"

Made with NaturalEarth | Elastic Maps Service

\",\"name\":\"World Countries\",\"weight\":1,\"format\":{\"type\":\"geojson\"},\"url\":\"https://vector.maps.elastic.co/blob/5659313586569216?elastic_tile_service_tos=agree&my_app_version=6.2.3&license=77ab0ecf-a521-499d-bd52-fbd740bb81d0\",\"fields\":[{\"name\":\"iso2\",\"description\":\"Two letter abbreviation\"},{\"name\":\"name\",\"description\":\"Country name\"},{\"name\":\"iso3\",\"description\":\"Three letter abbreviation\"}],\"created_at\":\"2017-04-26T17:12:15.978370\",\"tags\":[],\"id\":5659313586569216,\"layerId\":\"elastic_maps_service.World Countries\"},\"selectedJoinField\":{\"name\":\"iso2\",\"description\":\"Two letter abbreviation\"},\"isDisplayWarning\":false,\"wms\":{\"enabled\":false,\"options\":{\"format\":\"image/png\",\"transparent\":true},\"baseLayersAreLoaded\":{},\"tmsLayers\":[{\"id\":\"road_map\",\"url\":\"https://tiles.maps.elastic.co/v2/default/{z}/{x}/{y}.png?elastic_tile_service_tos=agree&my_app_name=kibana&my_app_version=6.2.3&license=77ab0ecf-a521-499d-bd52-fbd740bb81d0\",\"minZoom\":0,\"maxZoom\":18,\"attribution\":\"

© OpenStreetMap contributors | Elastic Maps Service

\",\"subdomains\":[]}],\"selectedTmsLayer\":{\"id\":\"road_map\",\"url\":\"https://tiles.maps.elastic.co/v2/default/{z}/{x}/{y}.png?elastic_tile_service_tos=agree&my_app_name=kibana&my_app_version=6.2.3&license=77ab0ecf-a521-499d-bd52-fbd740bb81d0\",\"minZoom\":0,\"maxZoom\":18,\"attribution\":\"

© OpenStreetMap contributors | Elastic Maps Service

\",\"subdomains\":[]}},\"mapZoom\":2,\"mapCenter\":[0,0],\"outlineWeight\":1,\"showAllShapes\":true,\"emsHotLink\":null},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"cardinality\",\"schema\":\"metric\",\"params\":{\"field\":\"clientip\",\"customLabel\":\"Unique Visitors\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"geo.src\",\"size\":50,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}", + "uiStateJSON": "{}", + "description": "", + "version": 1, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + } + }, + "references": [ + { + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern", + "id": "90943e30-9a47-11e8-b64d-95841ca0b247" + } + ], + "migrationVersion": { + "visualization": "7.2.0" + } + }, + { + "id": "935afa20-e0cd-11e7-9d07-1398ccfcefa3", + "type": "visualization", + "updated_at": "2019-07-08T15:35:44.395Z", + "version": "WzExLDFd", + "attributes": { + "title": "[Logs] Heatmap", + "visState": "{\"title\":\"[Logs] Heatmap\",\"type\":\"heatmap\",\"params\":{\"type\":\"heatmap\",\"addTooltip\":true,\"addLegend\":true,\"enableHover\":true,\"legendPosition\":\"right\",\"times\":[],\"colorsNumber\":10,\"colorSchema\":\"Reds\",\"setColorRange\":false,\"colorsRange\":[],\"invertColors\":false,\"percentageMode\":false,\"valueAxes\":[{\"show\":false,\"id\":\"ValueAxis-1\",\"type\":\"value\",\"scale\":{\"type\":\"linear\",\"defaultYExtents\":false},\"labels\":{\"show\":false,\"rotate\":0,\"color\":\"#555\",\"overwriteColor\":false}}]},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"cardinality\",\"schema\":\"metric\",\"params\":{\"field\":\"clientip\"}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"geo.src\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Country Source\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"hour_of_day\",\"size\":25,\"order\":\"asc\",\"orderBy\":\"_key\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Hour of Day\"}}]}", + "uiStateJSON": "{\"vis\":{\"defaultColors\":{\"0 - 4\":\"rgb(255,245,240)\",\"4 - 8\":\"rgb(254,228,216)\",\"8 - 12\":\"rgb(253,202,181)\",\"12 - 16\":\"rgb(252,171,142)\",\"16 - 20\":\"rgb(252,138,106)\",\"20 - 24\":\"rgb(251,106,74)\",\"24 - 28\":\"rgb(241,68,50)\",\"28 - 32\":\"rgb(217,38,35)\",\"32 - 36\":\"rgb(188,20,26)\",\"36 - 40\":\"rgb(152,12,19)\"}}}", + "description": "", + "version": 1, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + } + }, + "references": [ + { + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern", + "id": "90943e30-9a47-11e8-b64d-95841ca0b247" + } + ], + "migrationVersion": { + "visualization": "7.2.0" + } + }, + { + "id": "4eb6e500-e1c7-11e7-b6d5-4dc382ef7f5b", + "type": "visualization", + "updated_at": "2019-07-08T15:35:44.395Z", + "version": "WzEyLDFd", + "attributes": { + "title": "[Logs] Host, Visits and Bytes Table", + "visState": "{\"title\":\"[Logs] Host, Visits and Bytes Table\",\"type\":\"metrics\",\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"table\",\"series\":[{\"id\":\"bd09d600-e5b1-11e7-bfc2-a1f7e71965a1\",\"color\":\"#68BC00\",\"split_mode\":\"everything\",\"metrics\":[{\"id\":\"bd09d601-e5b1-11e7-bfc2-a1f7e71965a1\",\"type\":\"sum\",\"field\":\"bytes\"},{\"sigma\":\"\",\"id\":\"c9514c90-e5b1-11e7-bfc2-a1f7e71965a1\",\"type\":\"sum_bucket\",\"field\":\"bd09d601-e5b1-11e7-bfc2-a1f7e71965a1\"}],\"seperate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"bytes\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"color_rules\":[{\"id\":\"c0c668d0-e5b1-11e7-bfc2-a1f7e71965a1\"}],\"label\":\"Bytes (Total)\"},{\"id\":\"b7672c30-a6df-11e8-8b18-1da1dfc50975\",\"color\":\"#68BC00\",\"split_mode\":\"everything\",\"metrics\":[{\"id\":\"b7672c31-a6df-11e8-8b18-1da1dfc50975\",\"type\":\"sum\",\"field\":\"bytes\"}],\"seperate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"bytes\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"color_rules\":[{\"id\":\"c0c668d0-e5b1-11e7-bfc2-a1f7e71965a1\"}],\"label\":\"Bytes (Last Hour)\"},{\"id\":\"f2c20700-a6df-11e8-8b18-1da1dfc50975\",\"color\":\"#68BC00\",\"split_mode\":\"everything\",\"metrics\":[{\"id\":\"f2c20701-a6df-11e8-8b18-1da1dfc50975\",\"type\":\"cardinality\",\"field\":\"ip\"},{\"sigma\":\"\",\"id\":\"f46333e0-a6df-11e8-8b18-1da1dfc50975\",\"type\":\"sum_bucket\",\"field\":\"f2c20701-a6df-11e8-8b18-1da1dfc50975\"}],\"seperate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"label\":\"Unique Visits (Total)\",\"color_rules\":[{\"value\":1000,\"id\":\"2e963080-a6e0-11e8-8b18-1da1dfc50975\",\"text\":\"rgba(211,49,21,1)\",\"operator\":\"lt\"},{\"value\":1000,\"id\":\"3d4fb880-a6e0-11e8-8b18-1da1dfc50975\",\"text\":\"rgba(252,196,0,1)\",\"operator\":\"gte\"},{\"value\":1500,\"id\":\"435f8a20-a6e0-11e8-8b18-1da1dfc50975\",\"text\":\"rgba(104,188,0,1)\",\"operator\":\"gte\"}],\"offset_time\":\"\",\"value_template\":\"\",\"trend_arrows\":1},{\"id\":\"46fd7fc0-e5b1-11e7-bfc2-a1f7e71965a1\",\"color\":\"#68BC00\",\"split_mode\":\"everything\",\"metrics\":[{\"id\":\"46fd7fc1-e5b1-11e7-bfc2-a1f7e71965a1\",\"type\":\"cardinality\",\"field\":\"ip\"}],\"seperate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"label\":\"Unique Visits (Last Hour)\",\"color_rules\":[{\"value\":10,\"id\":\"4e90aeb0-a6e0-11e8-8b18-1da1dfc50975\",\"text\":\"rgba(211,49,21,1)\",\"operator\":\"lt\"},{\"value\":10,\"id\":\"6d59b1c0-a6e0-11e8-8b18-1da1dfc50975\",\"text\":\"rgba(252,196,0,1)\",\"operator\":\"gte\"},{\"value\":25,\"id\":\"77578670-a6e0-11e8-8b18-1da1dfc50975\",\"text\":\"rgba(104,188,0,1)\",\"operator\":\"gte\"}],\"offset_time\":\"\",\"value_template\":\"\",\"trend_arrows\":1}],\"time_field\":\"timestamp\",\"index_pattern\":\"kibana_sample_data_logs\",\"interval\":\"1h\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"bar_color_rules\":[{\"id\":\"e9b4e490-e1c6-11e7-b4f6-0f68c45f7387\"}],\"pivot_id\":\"extension.keyword\",\"pivot_label\":\"Type\",\"drilldown_url\":\"\",\"axis_scale\":\"normal\"},\"aggs\":[]}", + "uiStateJSON": "{}", + "description": "", + "version": 1, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" + } + }, + "references": [], + "migrationVersion": { + "visualization": "7.2.0" + } + }, + { + "id": "69a34b00-9ee8-11e7-8711-e7a007dcef99", + "type": "visualization", + "updated_at": "2019-07-08T15:35:44.395Z", + "version": "WzEzLDFd", + "attributes": { + "title": "[Logs] Goals", + "visState": "{\"title\":\"[Logs] Goals\",\"type\":\"gauge\",\"params\":{\"type\":\"gauge\",\"addTooltip\":true,\"addLegend\":false,\"gauge\":{\"verticalSplit\":false,\"extendRange\":true,\"percentageMode\":false,\"gaugeType\":\"Arc\",\"gaugeStyle\":\"Full\",\"backStyle\":\"Full\",\"orientation\":\"vertical\",\"colorSchema\":\"Green to Red\",\"gaugeColorMode\":\"Labels\",\"colorsRange\":[{\"from\":0,\"to\":500},{\"from\":500,\"to\":1000},{\"from\":1000,\"to\":1500}],\"invertColors\":true,\"labels\":{\"show\":false,\"color\":\"black\"},\"scale\":{\"show\":true,\"labels\":false,\"color\":\"#333\"},\"type\":\"meter\",\"style\":{\"bgWidth\":0.9,\"width\":0.9,\"mask\":false,\"bgMask\":false,\"maskBars\":50,\"bgFill\":\"#eee\",\"bgColor\":false,\"subText\":\"visitors\",\"fontSize\":60,\"labelColor\":true}},\"isDisplayWarning\":false},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"cardinality\",\"schema\":\"metric\",\"params\":{\"field\":\"clientip\",\"customLabel\":\"Unique Visitors\"}}]}", + "uiStateJSON": "{\"vis\":{\"defaultColors\":{\"0 - 500\":\"rgb(165,0,38)\",\"500 - 1000\":\"rgb(255,255,190)\",\"1000 - 1500\":\"rgb(0,104,55)\"},\"colors\":{\"75 - 100\":\"#629E51\",\"50 - 75\":\"#EAB839\",\"0 - 50\":\"#E24D42\",\"0 - 100\":\"#E24D42\",\"200 - 300\":\"#7EB26D\",\"500 - 1000\":\"#E5AC0E\",\"0 - 500\":\"#E24D42\",\"1000 - 1500\":\"#7EB26D\"},\"legendOpen\":true}}", + "description": "", + "version": 1, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + } + }, + "references": [ + { + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern", + "id": "90943e30-9a47-11e8-b64d-95841ca0b247" + } + ], + "migrationVersion": { + "visualization": "7.2.0" + } + }, + { + "id": "42b997f0-0c26-11e8-b0ec-3bb475f6b6ff", + "type": "visualization", + "updated_at": "2019-07-08T15:35:44.395Z", + "version": "WzE0LDFd", + "attributes": { + "title": "[Logs] File Type Scatter Plot", + "visState": "{\"title\":\"[Logs] File Type Scatter Plot\",\"type\":\"vega\",\"params\":{\"spec\":\"{\\n $schema: \\\"https://vega.github.io/schema/vega-lite/v2.json\\\"\\n // Use points for drawing to actually create a scatterplot\\n mark: point\\n // Specify where to load data from\\n data: {\\n // By using an object to the url parameter we will\\n // construct an Elasticsearch query\\n url: {\\n // Context == true means filters of the dashboard will be taken into account\\n %context%: true\\n // Specify on which field the time picker should operate\\n %timefield%: timestamp\\n // Specify the index pattern to load data from\\n index: kibana_sample_data_logs\\n // This body will be send to Elasticsearch's _search endpoint\\n // You can use everything the ES Query DSL supports here\\n body: {\\n // Set the size to load 10000 documents\\n size: 10000,\\n // Just ask for the fields we actually need for visualization\\n _source: [\\\"timestamp\\\", \\\"bytes\\\", \\\"extension\\\"]\\n }\\n }\\n // Tell Vega, that the array of data will be inside hits.hits of the response\\n // since the result returned from Elasticsearch fill have a format like:\\n // {\\n // hits: {\\n // total: 42000,\\n // max_score: 2,\\n // hits: [\\n // < our individual documents >\\n // ]\\n // }\\n // }\\n format: { property: \\\"hits.hits\\\" }\\n }\\n // You can do transformation and calculation of the data before drawing it\\n transform: [\\n // Since timestamp is a string value, we need to convert it to a unix timestamp\\n // so that Vega can work on it properly.\\n {\\n // Convert _source.timestamp field to a date\\n calculate: \\\"toDate(datum._source['timestamp'])\\\"\\n // Store the result in a field named \\\"time\\\" in the object\\n as: \\\"time\\\"\\n }\\n ]\\n // Specify what data will be drawn on which axis\\n encoding: {\\n x: {\\n // Draw the time field on the x-axis in temporal mode (i.e. as a time axis)\\n field: time\\n type: temporal\\n // Hide the axis label for the x-axis\\n axis: { title: false }\\n }\\n y: {\\n // Draw the bytes of each document on the y-axis\\n field: _source.bytes\\n // Mark the y-axis as quantitative\\n type: quantitative\\n // Specify the label for this axis\\n axis: { title: \\\"Transferred bytes\\\" }\\n }\\n color: {\\n // Make the color of each point depend on the _source.extension field\\n field: _source.extension\\n // Treat different values as completely unrelated values to each other.\\n // You could switch this to quantitative if you have a numeric field and\\n // want to create a color scale from one color to another depending on that\\n // field's value.\\n type: nominal\\n // Rename the legend title so it won't just state: \\\"_source.extension\\\"\\n legend: { title: 'File type' }\\n }\\n shape: {\\n // Also make the shape of each point dependent on the extension.\\n field: _source.extension\\n type: nominal\\n }\\n }\\n}\"},\"aggs\":[]}", + "uiStateJSON": "{}", + "description": "", + "version": 1, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" + } + }, + "references": [], + "migrationVersion": { + "visualization": "7.2.0" + } + }, + { + "id": "7cbd2350-2223-11e8-b802-5bcf64c2cfb4", + "type": "visualization", + "updated_at": "2019-07-08T15:35:44.395Z", + "version": "WzE1LDFd", + "attributes": { + "title": "[Logs] Source and Destination Sankey Chart", + "visState": "{\"title\":\"[Logs] Source and Destination Sankey Chart\",\"type\":\"vega\",\"params\":{\"spec\":\"{ \\n $schema: https://vega.github.io/schema/vega/v3.0.json\\n data: [\\n\\t{\\n \\t// query ES based on the currently selected time range and filter string\\n \\tname: rawData\\n \\turl: {\\n \\t%context%: true\\n \\t%timefield%: timestamp\\n \\tindex: kibana_sample_data_logs\\n \\tbody: {\\n \\tsize: 0\\n \\taggs: {\\n \\ttable: {\\n \\tcomposite: {\\n \\tsize: 10000\\n \\tsources: [\\n \\t{\\n \\tstk1: {\\n \\tterms: {field: \\\"geo.src\\\"}\\n \\t}\\n \\t}\\n \\t{\\n \\tstk2: {\\n \\tterms: {field: \\\"geo.dest\\\"}\\n \\t}\\n \\t}\\n \\t]\\n \\t}\\n \\t}\\n \\t}\\n \\t}\\n \\t}\\n \\t// From the result, take just the data we are interested in\\n \\tformat: {property: \\\"aggregations.table.buckets\\\"}\\n \\t// Convert key.stk1 -> stk1 for simpler access below\\n \\ttransform: [\\n \\t{type: \\\"formula\\\", expr: \\\"datum.key.stk1\\\", as: \\\"stk1\\\"}\\n \\t{type: \\\"formula\\\", expr: \\\"datum.key.stk2\\\", as: \\\"stk2\\\"}\\n \\t{type: \\\"formula\\\", expr: \\\"datum.doc_count\\\", as: \\\"size\\\"}\\n \\t]\\n\\t}\\n\\t{\\n \\tname: nodes\\n \\tsource: rawData\\n \\ttransform: [\\n \\t// when a country is selected, filter out unrelated data\\n \\t{\\n \\ttype: filter\\n \\texpr: !groupSelector || groupSelector.stk1 == datum.stk1 || groupSelector.stk2 == datum.stk2\\n \\t}\\n \\t// Set new key for later lookups - identifies each node\\n \\t{type: \\\"formula\\\", expr: \\\"datum.stk1+datum.stk2\\\", as: \\\"key\\\"}\\n \\t// instead of each table row, create two new rows,\\n \\t// one for the source (stack=stk1) and one for destination node (stack=stk2).\\n \\t// The country code stored in stk1 and stk2 fields is placed into grpId field.\\n \\t{\\n \\ttype: fold\\n \\tfields: [\\\"stk1\\\", \\\"stk2\\\"]\\n \\tas: [\\\"stack\\\", \\\"grpId\\\"]\\n \\t}\\n \\t// Create a sortkey, different for stk1 and stk2 stacks.\\n \\t{\\n \\ttype: formula\\n \\texpr: datum.stack == 'stk1' ? datum.stk1+datum.stk2 : datum.stk2+datum.stk1\\n \\tas: sortField\\n \\t}\\n \\t// Calculate y0 and y1 positions for stacking nodes one on top of the other,\\n \\t// independently for each stack, and ensuring they are in the proper order,\\n \\t// alphabetical from the top (reversed on the y axis)\\n \\t{\\n \\ttype: stack\\n \\tgroupby: [\\\"stack\\\"]\\n \\tsort: {field: \\\"sortField\\\", order: \\\"descending\\\"}\\n \\tfield: size\\n \\t}\\n \\t// calculate vertical center point for each node, used to draw edges\\n \\t{type: \\\"formula\\\", expr: \\\"(datum.y0+datum.y1)/2\\\", as: \\\"yc\\\"}\\n \\t]\\n\\t}\\n\\t{\\n \\tname: groups\\n \\tsource: nodes\\n \\ttransform: [\\n \\t// combine all nodes into country groups, summing up the doc counts\\n \\t{\\n \\ttype: aggregate\\n \\tgroupby: [\\\"stack\\\", \\\"grpId\\\"]\\n \\tfields: [\\\"size\\\"]\\n \\tops: [\\\"sum\\\"]\\n \\tas: [\\\"total\\\"]\\n \\t}\\n \\t// re-calculate the stacking y0,y1 values\\n \\t{\\n \\ttype: stack\\n \\tgroupby: [\\\"stack\\\"]\\n \\tsort: {field: \\\"grpId\\\", order: \\\"descending\\\"}\\n \\tfield: total\\n \\t}\\n \\t// project y0 and y1 values to screen coordinates\\n \\t// doing it once here instead of doing it several times in marks\\n \\t{type: \\\"formula\\\", expr: \\\"scale('y', datum.y0)\\\", as: \\\"scaledY0\\\"}\\n \\t{type: \\\"formula\\\", expr: \\\"scale('y', datum.y1)\\\", as: \\\"scaledY1\\\"}\\n \\t// boolean flag if the label should be on the right of the stack\\n \\t{type: \\\"formula\\\", expr: \\\"datum.stack == 'stk1'\\\", as: \\\"rightLabel\\\"}\\n \\t// Calculate traffic percentage for this country using \\\"y\\\" scale\\n \\t// domain upper bound, which represents the total traffic\\n \\t{\\n \\ttype: formula\\n \\texpr: datum.total/domain('y')[1]\\n \\tas: percentage\\n \\t}\\n \\t]\\n\\t}\\n\\t{\\n \\t// This is a temp lookup table with all the 'stk2' stack nodes\\n \\tname: destinationNodes\\n \\tsource: nodes\\n \\ttransform: [\\n \\t{type: \\\"filter\\\", expr: \\\"datum.stack == 'stk2'\\\"}\\n \\t]\\n\\t}\\n\\t{\\n \\tname: edges\\n \\tsource: nodes\\n \\ttransform: [\\n \\t// we only want nodes from the left stack\\n \\t{type: \\\"filter\\\", expr: \\\"datum.stack == 'stk1'\\\"}\\n \\t// find corresponding node from the right stack, keep it as \\\"target\\\"\\n \\t{\\n \\ttype: lookup\\n \\tfrom: destinationNodes\\n \\tkey: key\\n \\tfields: [\\\"key\\\"]\\n \\tas: [\\\"target\\\"]\\n \\t}\\n \\t// calculate SVG link path between stk1 and stk2 stacks for the node pair\\n \\t{\\n \\ttype: linkpath\\n \\torient: horizontal\\n \\tshape: diagonal\\n \\tsourceY: {expr: \\\"scale('y', datum.yc)\\\"}\\n \\tsourceX: {expr: \\\"scale('x', 'stk1') + bandwidth('x')\\\"}\\n \\ttargetY: {expr: \\\"scale('y', datum.target.yc)\\\"}\\n \\ttargetX: {expr: \\\"scale('x', 'stk2')\\\"}\\n \\t}\\n \\t// A little trick to calculate the thickness of the line.\\n \\t// The value needs to be the same as the hight of the node, but scaling\\n \\t// size to screen's height gives inversed value because screen's Y\\n \\t// coordinate goes from the top to the bottom, whereas the graph's Y=0\\n \\t// is at the bottom. So subtracting scaled doc count from screen height\\n \\t// (which is the \\\"lower\\\" bound of the \\\"y\\\" scale) gives us the right value\\n \\t{\\n \\ttype: formula\\n \\texpr: range('y')[0]-scale('y', datum.size)\\n \\tas: strokeWidth\\n \\t}\\n \\t// Tooltip needs individual link's percentage of all traffic\\n \\t{\\n \\ttype: formula\\n \\texpr: datum.size/domain('y')[1]\\n \\tas: percentage\\n \\t}\\n \\t]\\n\\t}\\n ]\\n scales: [\\n\\t{\\n \\t// calculates horizontal stack positioning\\n \\tname: x\\n \\ttype: band\\n \\trange: width\\n \\tdomain: [\\\"stk1\\\", \\\"stk2\\\"]\\n \\tpaddingOuter: 0.05\\n \\tpaddingInner: 0.95\\n\\t}\\n\\t{\\n \\t// this scale goes up as high as the highest y1 value of all nodes\\n \\tname: y\\n \\ttype: linear\\n \\trange: height\\n \\tdomain: {data: \\\"nodes\\\", field: \\\"y1\\\"}\\n\\t}\\n\\t{\\n \\t// use rawData to ensure the colors stay the same when clicking.\\n \\tname: color\\n \\ttype: ordinal\\n \\trange: category\\n \\tdomain: {data: \\\"rawData\\\", field: \\\"stk1\\\"}\\n\\t}\\n\\t{\\n \\t// this scale is used to map internal ids (stk1, stk2) to stack names\\n \\tname: stackNames\\n \\ttype: ordinal\\n \\trange: [\\\"Source\\\", \\\"Destination\\\"]\\n \\tdomain: [\\\"stk1\\\", \\\"stk2\\\"]\\n\\t}\\n ]\\n axes: [\\n\\t{\\n \\t// x axis should use custom label formatting to print proper stack names\\n \\torient: bottom\\n \\tscale: x\\n \\tencode: {\\n \\tlabels: {\\n \\tupdate: {\\n \\ttext: {scale: \\\"stackNames\\\", field: \\\"value\\\"}\\n \\t}\\n \\t}\\n \\t}\\n\\t}\\n\\t{orient: \\\"left\\\", scale: \\\"y\\\"}\\n ]\\n marks: [\\n\\t{\\n \\t// draw the connecting line between stacks\\n \\ttype: path\\n \\tname: edgeMark\\n \\tfrom: {data: \\\"edges\\\"}\\n \\t// this prevents some autosizing issues with large strokeWidth for paths\\n \\tclip: true\\n \\tencode: {\\n \\tupdate: {\\n \\t// By default use color of the left node, except when showing traffic\\n \\t// from just one country, in which case use destination color.\\n \\tstroke: [\\n \\t{\\n \\ttest: groupSelector && groupSelector.stack=='stk1'\\n \\tscale: color\\n \\tfield: stk2\\n \\t}\\n \\t{scale: \\\"color\\\", field: \\\"stk1\\\"}\\n \\t]\\n \\tstrokeWidth: {field: \\\"strokeWidth\\\"}\\n \\tpath: {field: \\\"path\\\"}\\n \\t// when showing all traffic, and hovering over a country,\\n \\t// highlight the traffic from that country.\\n \\tstrokeOpacity: {\\n \\tsignal: !groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 0.9 : 0.3\\n \\t}\\n \\t// Ensure that the hover-selected edges show on top\\n \\tzindex: {\\n \\tsignal: !groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 1 : 0\\n \\t}\\n \\t// format tooltip string\\n \\ttooltip: {\\n \\tsignal: datum.stk1 + ' → ' + datum.stk2 + '\\t' + format(datum.size, ',.0f') + ' (' + format(datum.percentage, '.1%') + ')'\\n \\t}\\n \\t}\\n \\t// Simple mouseover highlighting of a single line\\n \\thover: {\\n \\tstrokeOpacity: {value: 1}\\n \\t}\\n \\t}\\n\\t}\\n\\t{\\n \\t// draw stack groups (countries)\\n \\ttype: rect\\n \\tname: groupMark\\n \\tfrom: {data: \\\"groups\\\"}\\n \\tencode: {\\n \\tenter: {\\n \\tfill: {scale: \\\"color\\\", field: \\\"grpId\\\"}\\n \\twidth: {scale: \\\"x\\\", band: 1}\\n \\t}\\n \\tupdate: {\\n \\tx: {scale: \\\"x\\\", field: \\\"stack\\\"}\\n \\ty: {field: \\\"scaledY0\\\"}\\n \\ty2: {field: \\\"scaledY1\\\"}\\n \\tfillOpacity: {value: 0.6}\\n \\ttooltip: {\\n \\tsignal: datum.grpId + ' ' + format(datum.total, ',.0f') + ' (' + format(datum.percentage, '.1%') + ')'\\n \\t}\\n \\t}\\n \\thover: {\\n \\tfillOpacity: {value: 1}\\n \\t}\\n \\t}\\n\\t}\\n\\t{\\n \\t// draw country code labels on the inner side of the stack\\n \\ttype: text\\n \\tfrom: {data: \\\"groups\\\"}\\n \\t// don't process events for the labels - otherwise line mouseover is unclean\\n \\tinteractive: false\\n \\tencode: {\\n \\tupdate: {\\n \\t// depending on which stack it is, position x with some padding\\n \\tx: {\\n \\tsignal: scale('x', datum.stack) + (datum.rightLabel ? bandwidth('x') + 8 : -8)\\n \\t}\\n \\t// middle of the group\\n \\tyc: {signal: \\\"(datum.scaledY0 + datum.scaledY1)/2\\\"}\\n \\talign: {signal: \\\"datum.rightLabel ? 'left' : 'right'\\\"}\\n \\tbaseline: {value: \\\"middle\\\"}\\n \\tfontWeight: {value: \\\"bold\\\"}\\n \\t// only show text label if the group's height is large enough\\n \\ttext: {signal: \\\"abs(datum.scaledY0-datum.scaledY1) > 13 ? datum.grpId : ''\\\"}\\n \\t}\\n \\t}\\n\\t}\\n\\t{\\n \\t// Create a \\\"show all\\\" button. Shown only when a country is selected.\\n \\ttype: group\\n \\tdata: [\\n \\t// We need to make the button show only when groupSelector signal is true.\\n \\t// Each mark is drawn as many times as there are elements in the backing data.\\n \\t// Which means that if values list is empty, it will not be drawn.\\n \\t// Here I create a data source with one empty object, and filter that list\\n \\t// based on the signal value. This can only be done in a group.\\n \\t{\\n \\tname: dataForShowAll\\n \\tvalues: [{}]\\n \\ttransform: [{type: \\\"filter\\\", expr: \\\"groupSelector\\\"}]\\n \\t}\\n \\t]\\n \\t// Set button size and positioning\\n \\tencode: {\\n \\tenter: {\\n \\txc: {signal: \\\"width/2\\\"}\\n \\ty: {value: 30}\\n \\twidth: {value: 80}\\n \\theight: {value: 30}\\n \\t}\\n \\t}\\n \\tmarks: [\\n \\t{\\n \\t// This group is shown as a button with rounded corners.\\n \\ttype: group\\n \\t// mark name allows signal capturing\\n \\tname: groupReset\\n \\t// Only shows button if dataForShowAll has values.\\n \\tfrom: {data: \\\"dataForShowAll\\\"}\\n \\tencode: {\\n \\tenter: {\\n \\tcornerRadius: {value: 6}\\n \\tfill: {value: \\\"#F5F7FA\\\"}\\n \\tstroke: {value: \\\"#c1c1c1\\\"}\\n \\tstrokeWidth: {value: 2}\\n \\t// use parent group's size\\n \\theight: {\\n \\tfield: {group: \\\"height\\\"}\\n \\t}\\n \\twidth: {\\n \\tfield: {group: \\\"width\\\"}\\n \\t}\\n \\t}\\n \\tupdate: {\\n \\t// groups are transparent by default\\n \\topacity: {value: 1}\\n \\t}\\n \\thover: {\\n \\topacity: {value: 0.7}\\n \\t}\\n \\t}\\n \\tmarks: [\\n \\t{\\n \\ttype: text\\n \\t// if true, it will prevent clicking on the button when over text.\\n \\tinteractive: false\\n \\tencode: {\\n \\tenter: {\\n \\t// center text in the paren group\\n \\txc: {\\n \\tfield: {group: \\\"width\\\"}\\n \\tmult: 0.5\\n \\t}\\n \\tyc: {\\n \\tfield: {group: \\\"height\\\"}\\n \\tmult: 0.5\\n \\toffset: 2\\n \\t}\\n \\talign: {value: \\\"center\\\"}\\n \\tbaseline: {value: \\\"middle\\\"}\\n \\tfontWeight: {value: \\\"bold\\\"}\\n \\ttext: {value: \\\"Show All\\\"}\\n \\t}\\n \\t}\\n \\t}\\n \\t]\\n \\t}\\n \\t]\\n\\t}\\n ]\\n signals: [\\n\\t{\\n \\t// used to highlight traffic to/from the same country\\n \\tname: groupHover\\n \\tvalue: {}\\n \\ton: [\\n \\t{\\n \\tevents: @groupMark:mouseover\\n \\tupdate: \\\"{stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}\\\"\\n \\t}\\n \\t{events: \\\"mouseout\\\", update: \\\"{}\\\"}\\n \\t]\\n\\t}\\n\\t// used to filter only the data related to the selected country\\n\\t{\\n \\tname: groupSelector\\n \\tvalue: false\\n \\ton: [\\n \\t{\\n \\t// Clicking groupMark sets this signal to the filter values\\n \\tevents: @groupMark:click!\\n \\tupdate: \\\"{stack:datum.stack, stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}\\\"\\n \\t}\\n \\t{\\n \\t// Clicking \\\"show all\\\" button, or double-clicking anywhere resets it\\n \\tevents: [\\n \\t{type: \\\"click\\\", markname: \\\"groupReset\\\"}\\n \\t{type: \\\"dblclick\\\"}\\n \\t]\\n \\tupdate: \\\"false\\\"\\n \\t}\\n \\t]\\n\\t}\\n ]\\n}\\n\"},\"aggs\":[]}", + "uiStateJSON": "{}", + "description": "", + "version": 1, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" + } + }, + "references": [], + "migrationVersion": { + "visualization": "7.2.0" + } + }, + { + "id": "314c6f60-2224-11e8-b802-5bcf64c2cfb4", + "type": "visualization", + "updated_at": "2019-07-08T15:35:44.395Z", + "version": "WzE2LDFd", + "attributes": { + "title": "[Logs] Response Codes Over Time + Annotations", + "visState": "{\"title\":\"[Logs] Response Codes Over Time + Annotations\",\"type\":\"metrics\",\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(115,216,255,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"cardinality\",\"field\":\"ip\"}],\"seperate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"percent\",\"chart_type\":\"line\",\"line_width\":\"2\",\"point_size\":\"0\",\"fill\":\"0.5\",\"stacked\":\"percent\",\"terms_field\":\"response.keyword\",\"terms_order_by\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"label\":\"Response Code Count\",\"split_color_mode\":\"gradient\"}],\"time_field\":\"timestamp\",\"index_pattern\":\"kibana_sample_data_logs\",\"interval\":\">=4h\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"annotations\":[{\"fields\":\"geo.src, host\",\"template\":\"Security Error from {{geo.src}} on {{host}}\",\"index_pattern\":\"kibana_sample_data_logs\",\"query_string\":\"tags:error AND tags:security\",\"id\":\"bd7548a0-2223-11e8-832f-d5027f3c8a47\",\"color\":\"rgba(211,49,21,1)\",\"time_field\":\"timestamp\",\"icon\":\"fa-asterisk\",\"ignore_global_filters\":1,\"ignore_panel_filters\":1}],\"legend_position\":\"bottom\",\"axis_scale\":\"normal\",\"drop_last_bucket\":0},\"aggs\":[]}", + "uiStateJSON": "{}", + "description": "", + "version": 1, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" + } + }, + "references": [], + "migrationVersion": { + "visualization": "7.2.0" + } + }, + { + "id": "24a3e970-4257-11e8-b3aa-73fdaf54bfc9", + "type": "visualization", + "updated_at": "2019-07-08T15:35:44.395Z", + "version": "WzE3LDFd", + "attributes": { + "title": "[Logs] Input Controls", + "visState": "{\"title\":\"[Logs] Input Controls\",\"type\":\"input_control_vis\",\"params\":{\"controls\":[{\"id\":\"1523980210832\",\"fieldName\":\"geo.src\",\"label\":\"Source Country\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"size\":100,\"order\":\"desc\"},\"parent\":\"\",\"indexPatternRefName\":\"control_0_index_pattern\"},{\"id\":\"1523980191978\",\"fieldName\":\"machine.os.keyword\",\"label\":\"OS\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"size\":100,\"order\":\"desc\"},\"parent\":\"1523980210832\",\"indexPatternRefName\":\"control_1_index_pattern\"},{\"id\":\"1523980232790\",\"fieldName\":\"bytes\",\"label\":\"Bytes\",\"type\":\"range\",\"options\":{\"decimalPlaces\":0,\"step\":1024},\"indexPatternRefName\":\"control_2_index_pattern\"}],\"updateFiltersOnChange\":true,\"useTimeFilter\":true,\"pinFilters\":false},\"aggs\":[]}", + "uiStateJSON": "{}", + "description": "", + "version": 1, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" + } + }, + "references": [ + { + "name": "control_0_index_pattern", + "type": "index-pattern", + "id": "90943e30-9a47-11e8-b64d-95841ca0b247" + }, + { + "name": "control_1_index_pattern", + "type": "index-pattern", + "id": "90943e30-9a47-11e8-b64d-95841ca0b247" + }, + { + "name": "control_2_index_pattern", + "type": "index-pattern", + "id": "90943e30-9a47-11e8-b64d-95841ca0b247" + } + ], + "migrationVersion": { + "visualization": "7.2.0" + } + }, + { + "id": "14e2e710-4258-11e8-b3aa-73fdaf54bfc9", + "type": "visualization", + "updated_at": "2019-07-08T15:35:44.395Z", + "version": "WzE4LDFd", + "attributes": { + "title": "[Logs] Visitors by OS", + "visState": "{\"title\":\"[Logs] Visitors by OS\",\"type\":\"pie\",\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":true,\"values\":true,\"last_level\":true,\"truncate\":100}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"machine.os.keyword\",\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"size\":10,\"order\":\"desc\",\"orderBy\":\"1\"}}]}", + "uiStateJSON": "{}", + "description": "", + "version": 1, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + } + }, + "references": [ + { + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern", + "id": "90943e30-9a47-11e8-b64d-95841ca0b247" + } + ], + "migrationVersion": { + "visualization": "7.2.0" + } + }, + { + "id": "47f2c680-a6e3-11e8-94b4-c30c0228351b", + "type": "visualization", + "updated_at": "2019-07-08T15:35:44.395Z", + "version": "WzE5LDFd", + "attributes": { + "title": "[Logs] Markdown Instructions", + "visState": "{\"title\":\"[Logs] Markdown Instructions\",\"type\":\"markdown\",\"params\":{\"fontSize\":12,\"openLinksInNewTab\":true,\"markdown\":\"### Sample Logs Data\\nThis dashboard contains sample data for you to play with. You can view it, search it, and interact with the visualizations. For more information about Kibana, check our [docs](https://www.elastic.co/guide/en/kibana/current/index.html).\"},\"aggs\":[]}", + "uiStateJSON": "{}", + "description": "", + "version": 1, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" + } + }, + "references": [], + "migrationVersion": { + "visualization": "7.2.0" + } + }, + { + "id": "90943e30-9a47-11e8-b64d-95841ca0b247", + "type": "index-pattern", + "updated_at": "2019-07-08T15:35:44.395Z", + "version": "WzIwLDFd", + "attributes": { + "title": "kibana_sample_data_logs", + "timeFieldName": "timestamp", + "fields": "[{\"name\":\"@timestamp\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"_id\",\"type\":\"string\",\"esTypes\":[\"_id\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"esTypes\":[\"_index\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"esTypes\":[\"_source\"],\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"esTypes\":[\"_type\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"agent\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"agent.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"parent\":\"agent\",\"subType\":\"multi\"},{\"name\":\"bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"extension\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"extension.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"parent\":\"extension\",\"subType\":\"multi\"},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"esTypes\":[\"geo_point\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"host.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"parent\":\"host\",\"subType\":\"multi\"},{\"name\":\"index\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"index.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"parent\":\"index\",\"subType\":\"multi\"},{\"name\":\"ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"machine.os.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"parent\":\"machine.os\",\"subType\":\"multi\"},{\"name\":\"machine.ram\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"memory\",\"type\":\"number\",\"esTypes\":[\"double\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"message\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"message.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"parent\":\"message\",\"subType\":\"multi\"},{\"name\":\"phpmemory\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"referer\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"request\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"request.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"parent\":\"request\",\"subType\":\"multi\"},{\"name\":\"response\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"response.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"parent\":\"response\",\"subType\":\"multi\"},{\"name\":\"tags\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"tags.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"parent\":\"tags\",\"subType\":\"multi\"},{\"name\":\"timestamp\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"url.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"parent\":\"url\",\"subType\":\"multi\"},{\"name\":\"utc_time\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"hour_of_day\",\"type\":\"number\",\"count\":0,\"scripted\":true,\"script\":\"doc['timestamp'].value.getHour()\",\"lang\":\"painless\",\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false}]", + "fieldFormatMap": "{\"hour_of_day\":{}}" + }, + "references": [], + "migrationVersion": { + "index-pattern": "6.5.0" + } + } + ] +} \ No newline at end of file diff --git a/libs/go-kibana-rest/go.mod b/libs/go-kibana-rest/go.mod new file mode 100644 index 000000000..e2d53ae90 --- /dev/null +++ b/libs/go-kibana-rest/go.mod @@ -0,0 +1,25 @@ +module github.com/disaster37/go-kibana-rest/v8 + +go 1.19 + +require ( + github.com/go-resty/resty/v2 v2.7.0 + github.com/sirupsen/logrus v1.9.0 + github.com/stretchr/testify v1.8.1 + github.com/x-cray/logrus-prefixed-formatter v0.5.2 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/mattn/go-colorable v0.1.8 // indirect + github.com/mattn/go-isatty v0.0.12 // indirect + github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect + github.com/onsi/ginkgo v1.16.5 // indirect + github.com/onsi/gomega v1.24.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + golang.org/x/crypto v0.1.0 // indirect + golang.org/x/net v0.1.0 // indirect + golang.org/x/sys v0.1.0 // indirect + golang.org/x/term v0.1.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/libs/go-kibana-rest/go.sum b/libs/go-kibana-rest/go.sum new file mode 100644 index 000000000..4a88f4a05 --- /dev/null +++ b/libs/go-kibana-rest/go.sum @@ -0,0 +1,118 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= +github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.24.0 h1:+0glovB9Jd6z3VR+ScSwQqXVTIfJcGA9UBM8yzQxhqg= +github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg= +github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/libs/go-kibana-rest/kbapi/api._.go b/libs/go-kibana-rest/kbapi/api._.go new file mode 100644 index 000000000..d4d622d64 --- /dev/null +++ b/libs/go-kibana-rest/kbapi/api._.go @@ -0,0 +1,114 @@ +package kbapi + +import ( + "github.com/go-resty/resty/v2" +) + +// API handle the API specification +type API struct { + KibanaSpaces *KibanaSpacesAPI + KibanaRoleManagement *KibanaRoleManagementAPI + KibanaDashboard *KibanaDashboardAPI + KibanaSavedObject *KibanaSavedObjectAPI + KibanaStatus *KibanaStatusAPI + KibanaLogstashPipeline *KibanaLogstashPipelineAPI + KibanaShortenURL *KibanaShortenURLAPI +} + +// KibanaSpacesAPI handle the spaces API +type KibanaSpacesAPI struct { + Get KibanaSpaceGet + List KibanaSpaceList + Create KibanaSpaceCreate + Delete KibanaSpaceDelete + Update KibanaSpaceUpdate + CopySavedObjects KibanaSpaceCopySavedObjects +} + +// KibanaRoleManagementAPI handle the role management API +type KibanaRoleManagementAPI struct { + Get KibanaRoleManagementGet + List KibanaRoleManagementList + CreateOrUpdate KibanaRoleManagementCreateOrUpdate + Delete KibanaRoleManagementDelete +} + +// KibanaDashboardAPI handle the dashboard API +type KibanaDashboardAPI struct { + Export KibanaDashboardExport + Import KibanaDashboardImport +} + +// KibanaSavedObjectAPI handle the saved object API +type KibanaSavedObjectAPI struct { + Get KibanaSavedObjectGet + Find KibanaSavedObjectFind + Create KibanaSavedObjectCreate + Update KibanaSavedObjectUpdate + Delete KibanaSavedObjectDelete + Import KibanaSavedObjectImport + Export KibanaSavedObjectExport +} + +// KibanaStatusAPI handle the status API +type KibanaStatusAPI struct { + Get KibanaStatusGet +} + +// KibanaLogstashPipelineAPI handle the logstash configuration management API +type KibanaLogstashPipelineAPI struct { + Get KibanaLogstashPipelineGet + List KibanaLogstashPipelineList + CreateOrUpdate KibanaLogstashPipelineCreateOrUpdate + Delete KibanaLogstashPipelineDelete +} + +// KibanaShortenURLAPI handle the shorten URL API +type KibanaShortenURLAPI struct { + Create KibanaShortenURLCreate +} + +// New initialise the API implementation +func New(c *resty.Client) *API { + return &API{ + KibanaSpaces: &KibanaSpacesAPI{ + Get: newKibanaSpaceGetFunc(c), + List: newKibanaSpaceListFunc(c), + Create: newKibanaSpaceCreateFunc(c), + Update: newKibanaSpaceUpdateFunc(c), + Delete: newKibanaSpaceDeleteFunc(c), + CopySavedObjects: newKibanaSpaceCopySavedObjectsFunc(c), + }, + KibanaRoleManagement: &KibanaRoleManagementAPI{ + Get: newKibanaRoleManagementGetFunc(c), + List: newKibanaRoleManagementListFunc(c), + CreateOrUpdate: newKibanaRoleManagementCreateOrUpdateFunc(c), + Delete: newKibanaRoleManagementDeleteFunc(c), + }, + KibanaDashboard: &KibanaDashboardAPI{ + Export: newKibanaDashboardExportFunc(c), + Import: newKibanaDashboardImportFunc(c), + }, + KibanaSavedObject: &KibanaSavedObjectAPI{ + Get: newKibanaSavedObjectGetFunc(c), + Find: newKibanaSavedObjectFindFunc(c), + Create: newKibanaSavedObjectCreateFunc(c), + Update: newKibanaSavedObjectUpdateFunc(c), + Delete: newKibanaSavedObjectDeleteFunc(c), + Import: newKibanaSavedObjectImportFunc(c), + Export: newKibanaSavedObjectExportFunc(c), + }, + KibanaStatus: &KibanaStatusAPI{ + Get: newKibanaStatusGetFunc(c), + }, + KibanaLogstashPipeline: &KibanaLogstashPipelineAPI{ + Get: newKibanaLogstashPipelineGetFunc(c), + List: newKibanaLogstashPipelineListFunc(c), + CreateOrUpdate: newKibanaLogstashPipelineCreateOrUpdateFunc(c), + Delete: newKibanaLogstashPipelineDeleteFunc(c), + }, + KibanaShortenURL: &KibanaShortenURLAPI{ + Create: newKibanaShortenURLCreateFunc(c), + }, + } +} diff --git a/libs/go-kibana-rest/kbapi/api.kibana_dashboard.go b/libs/go-kibana-rest/kbapi/api.kibana_dashboard.go new file mode 100644 index 000000000..69be75594 --- /dev/null +++ b/libs/go-kibana-rest/kbapi/api.kibana_dashboard.go @@ -0,0 +1,114 @@ +package kbapi + +import ( + "encoding/json" + "fmt" + "github.com/go-resty/resty/v2" + log "github.com/sirupsen/logrus" + "strings" +) + +const ( + basePathKibanaDashboard = "/api/kibana/dashboards" // Base URL to access on Kibana dashboard +) + +// KibanaDashboardExport permit to export dashboard +type KibanaDashboardExport func(listID []string, kibanaSpace string) (map[string]interface{}, error) + +// KibanaDashboardImport permit to import dashboard +type KibanaDashboardImport func(data map[string]interface{}, listExcludeType []string, force bool, kibanaSpace string) error + +// newKibanaDashboardExportFunc permit to export Kibana dashboard by its names +func newKibanaDashboardExportFunc(c *resty.Client) KibanaDashboardExport { + return func(listID []string, kibanaSpace string) (map[string]interface{}, error) { + + if len(listID) == 0 { + return nil, NewAPIError(600, "You must provide on or more dashboard ID") + } + log.Debug("listID: ", listID) + log.Debug("kibanaSpace: ", kibanaSpace) + + var path string + if kibanaSpace == "" || kibanaSpace == "default" { + path = fmt.Sprintf("%s/export", basePathKibanaDashboard) + } else { + path = fmt.Sprintf("/s/%s%s/export", kibanaSpace, basePathKibanaDashboard) + } + + log.Debugf("Url to export: %s", path) + + query := fmt.Sprintf("dashboard=%s", strings.Join(listID, ",")) + resp, err := c.R().SetQueryString(query).Get(path) + if err != nil { + return nil, err + } + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + if resp.StatusCode() == 404 { + return nil, nil + } + return nil, NewAPIError(resp.StatusCode(), resp.Status()) + + } + var data map[string]interface{} + err = json.Unmarshal(resp.Body(), &data) + if err != nil { + return nil, err + } + log.Debug("Data: ", data) + + return data, nil + } + +} + +// newKibanaDashboardImportFunc permit to import kibana dashboard +func newKibanaDashboardImportFunc(c *resty.Client) KibanaDashboardImport { + return func(data map[string]interface{}, listExcludeType []string, force bool, kibanaSpace string) error { + + if data == nil { + return NewAPIError(600, "You must provide one or more dashboard to import") + } + log.Debug("data: ", data) + log.Debug("List type to exclude: ", listExcludeType) + log.Debug("Force import: ", force) + log.Debug("KibanaSpace: ", kibanaSpace) + + var path string + if kibanaSpace == "" || kibanaSpace == "default" { + path = fmt.Sprintf("%s/import", basePathKibanaDashboard) + } else { + path = fmt.Sprintf("/s/%s%s/import", kibanaSpace, basePathKibanaDashboard) + } + + log.Debugf("URL to import %s", path) + + request := c.R().SetQueryString(fmt.Sprintf("force=%t", force)) + if len(listExcludeType) > 0 { + request = request.SetQueryString(fmt.Sprintf("exclude=%s", strings.Join(listExcludeType, ","))) + } + jsonData, err := json.Marshal(data) + if err != nil { + return err + } + resp, err := request.SetBody(jsonData).Post(path) + if err != nil { + return err + } + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + return NewAPIError(resp.StatusCode(), resp.Status()) + } + var dataResponse map[string]interface{} + err = json.Unmarshal(resp.Body(), &dataResponse) + if err != nil { + return err + } + log.Debug("Data response: ", dataResponse) + + // Need to manage error returned in response + + return nil + } + +} diff --git a/libs/go-kibana-rest/kbapi/api.kibana_dashboard_test.go b/libs/go-kibana-rest/kbapi/api.kibana_dashboard_test.go new file mode 100644 index 000000000..93150c668 --- /dev/null +++ b/libs/go-kibana-rest/kbapi/api.kibana_dashboard_test.go @@ -0,0 +1,46 @@ +package kbapi + +import ( + "encoding/json" + "os" + + "github.com/stretchr/testify/assert" +) + +func (s *KBAPITestSuite) TestKibanaDashboard() { + + // Import dashboard from fixtures + b, err := os.ReadFile("../fixtures/kibana-dashboard.json") + if err != nil { + panic(err) + } + data := make(map[string]interface{}) + if err = json.Unmarshal(b, &data); err != nil { + panic(err) + } + err = s.API.KibanaDashboard.Import(data, nil, true, "default") + assert.NoError(s.T(), err) + + // Export dashboard + data, err = s.API.KibanaDashboard.Export([]string{"edf84fe0-e1a0-11e7-b6d5-4dc382ef7f5b"}, "default") + assert.NoError(s.T(), err) + assert.NotNil(s.T(), data) + + // Import dashboard from fixtures in specific space + b, err = os.ReadFile("../fixtures/kibana-dashboard.json") + if err != nil { + panic(err) + } + data = make(map[string]interface{}) + if err = json.Unmarshal(b, &data); err != nil { + panic(err) + } + err = s.API.KibanaDashboard.Import(data, nil, true, "testacc") + assert.NoError(s.T(), err) + + // Export dashboard from specific space + data, err = s.API.KibanaDashboard.Export([]string{"edf84fe0-e1a0-11e7-b6d5-4dc382ef7f5b"}, "testacc") + assert.NoError(s.T(), err) + assert.NotNil(s.T(), data) + +} diff --git a/libs/go-kibana-rest/kbapi/api.kibana_logstash_pipeline.go b/libs/go-kibana-rest/kbapi/api.kibana_logstash_pipeline.go new file mode 100644 index 000000000..698e399b0 --- /dev/null +++ b/libs/go-kibana-rest/kbapi/api.kibana_logstash_pipeline.go @@ -0,0 +1,182 @@ +package kbapi + +import ( + "encoding/json" + "fmt" + + "github.com/go-resty/resty/v2" + log "github.com/sirupsen/logrus" +) + +const ( + basePathKibanaLogstashPipeline = "/api/logstash/pipeline" // Base URL to access on Kibana Logstash pipeline +) + +// LogstashPipeline is the Logstash pipeline object +type LogstashPipeline struct { + ID string `json:"id"` + Description string `json:"description,omitempty"` + Pipeline string `json:"pipeline,omitempty"` + Settings map[string]interface{} `json:"settings,omitempty"` + Username string `json:"username,omitempty"` +} + +type LogstashPipelineRequest struct { + Description string `json:"description,omitempty"` + Pipeline string `json:"pipeline,omitempty"` + Settings map[string]interface{} `json:"settings,omitempty"` + Username string `json:"username,omitempty"` +} + +// LogstashPipelinesList is the logstash pipeline list result when get the list +type LogstashPipelinesList struct { + Pipelines LogstashPipelines `json:"pipelines"` +} + +// LogstashPipelines is list of Logstash pipeline object +type LogstashPipelines []LogstashPipeline + +// KibanaLogstashPipelineCreateOrUpdate permit to create or update logstash pipeline +type KibanaLogstashPipelineCreateOrUpdate func(logstashPipeline *LogstashPipeline) (*LogstashPipeline, error) + +// KibanaLogstashPipelineGet permit to get the logstash pipeline +type KibanaLogstashPipelineGet func(id string) (*LogstashPipeline, error) + +// KibanaLogstashPipelineList permit to get all the logstash pipeline +type KibanaLogstashPipelineList func() (LogstashPipelines, error) + +// KibanaLogstashPipelineDelete permit to delete the logstash pipeline +type KibanaLogstashPipelineDelete func(id string) error + +// String permit to return LogstashPipeline object as JSON string +func (o *LogstashPipeline) String() string { + json, _ := json.Marshal(o) + return string(json) +} + +// newKibanaLogstashPipelineGetFunc permit to get the kibana role with it name +func newKibanaLogstashPipelineGetFunc(c *resty.Client) KibanaLogstashPipelineGet { + return func(id string) (*LogstashPipeline, error) { + + if id == "" { + return nil, NewAPIError(600, "You must provide logstash pipline ID") + } + log.Debug("ID: ", id) + + path := fmt.Sprintf("%s/%s", basePathKibanaLogstashPipeline, id) + resp, err := c.R().Get(path) + if err != nil { + return nil, err + } + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + if resp.StatusCode() == 404 { + return nil, nil + } + return nil, NewAPIError(resp.StatusCode(), resp.Status()) + } + logstashPipeline := &LogstashPipeline{} + err = json.Unmarshal(resp.Body(), logstashPipeline) + if err != nil { + return nil, err + } + log.Debug("LogstashPipeline: ", logstashPipeline) + + return logstashPipeline, nil + } +} + +// newKibanaLogstashPipelineListFunc permit to get all kibana role +func newKibanaLogstashPipelineListFunc(c *resty.Client) KibanaLogstashPipelineList { + return func() (LogstashPipelines, error) { + + path := fmt.Sprintf("%ss", basePathKibanaLogstashPipeline) + resp, err := c.R().Get(path) + if err != nil { + return nil, err + } + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + return nil, NewAPIError(resp.StatusCode(), resp.Status()) + } + logstashPipelinesList := &LogstashPipelinesList{} + err = json.Unmarshal(resp.Body(), logstashPipelinesList) + if err != nil { + return nil, err + } + log.Debug("LogstashPipelines: ", logstashPipelinesList) + + return logstashPipelinesList.Pipelines, nil + } + +} + +// newKibanaPipelineCreateOrUpdateFunc permit to create or update logstash pipeline +func newKibanaLogstashPipelineCreateOrUpdateFunc(c *resty.Client) KibanaLogstashPipelineCreateOrUpdate { + return func(logstashPipeline *LogstashPipeline) (*LogstashPipeline, error) { + + if logstashPipeline == nil { + return nil, NewAPIError(600, "You must provide the logstash pipeline object") + } + + log.Debug("LogstashPipeline: ", logstashPipeline) + + logstashPipelineRequest := &LogstashPipelineRequest{ + Description: logstashPipeline.Description, + Pipeline: logstashPipeline.Pipeline, + Settings: logstashPipeline.Settings, + } + + jsonData, err := json.Marshal(logstashPipelineRequest) + if err != nil { + return nil, err + } + + path := fmt.Sprintf("%s/%s", basePathKibanaLogstashPipeline, logstashPipeline.ID) + resp, err := c.R().SetBody(jsonData).Put(path) + if err != nil { + return nil, err + } + + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + return nil, NewAPIError(resp.StatusCode(), resp.Status()) + } + + // Retrive the object to return it + logstashPipeline, err = newKibanaLogstashPipelineGetFunc(c)(logstashPipeline.ID) + if err != nil { + return nil, err + } + if logstashPipeline == nil { + return nil, NewAPIError(404, "Logstash pipeline %s not found", logstashPipeline.ID) + } + + log.Debug("logstashPipeline: ", logstashPipeline) + + return logstashPipeline, nil + } +} + +// newKibanaLogstashPipelineDeleteFunc permit to delete logstash pipeline with it ID +func newKibanaLogstashPipelineDeleteFunc(c *resty.Client) KibanaLogstashPipelineDelete { + return func(id string) error { + + if id == "" { + return NewAPIError(600, "You must provide logstash pipeline ID") + } + log.Debug("ID: ", id) + + path := fmt.Sprintf("%s/%s", basePathKibanaLogstashPipeline, id) + resp, err := c.R().Delete(path) + if err != nil { + return err + } + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + return NewAPIError(resp.StatusCode(), resp.Status()) + } + + return nil + } +} diff --git a/libs/go-kibana-rest/kbapi/api.kibana_logstash_pipeline_test.go b/libs/go-kibana-rest/kbapi/api.kibana_logstash_pipeline_test.go new file mode 100644 index 000000000..de636de26 --- /dev/null +++ b/libs/go-kibana-rest/kbapi/api.kibana_logstash_pipeline_test.go @@ -0,0 +1,41 @@ +package kbapi + +import ( + "github.com/stretchr/testify/assert" +) + +func (s *KBAPITestSuite) TestKibanaLogstashPipeline() { + + // Create new logstash pipeline + logstashPipeline := &LogstashPipeline{ + ID: "test", + Description: "Acceptance test", + Pipeline: "input { stdin {} } output { stdout {} }", + Settings: map[string]interface{}{ + "queue.type": "persisted", + }, + } + logstashPipeline, err := s.API.KibanaLogstashPipeline.CreateOrUpdate(logstashPipeline) + assert.NoError(s.T(), err) + assert.NotNil(s.T(), logstashPipeline) + assert.Equal(s.T(), "test", logstashPipeline.ID) + + // Get logstash pipeline + logstashPipeline, err = s.API.KibanaLogstashPipeline.Get("test") + assert.NoError(s.T(), err) + assert.NotNil(s.T(), logstashPipeline) + assert.Equal(s.T(), "test", logstashPipeline.ID) + + // List logstash pipeline + logstashPipelines, err := s.API.KibanaLogstashPipeline.List() + assert.NoError(s.T(), err) + assert.NotEmpty(s.T(), logstashPipelines) + + // Delete logstash pipeline + err = s.API.KibanaLogstashPipeline.Delete("test") + assert.NoError(s.T(), err) + logstashPipeline, err = s.API.KibanaLogstashPipeline.Get("test") + assert.NoError(s.T(), err) + assert.Nil(s.T(), logstashPipeline) + +} diff --git a/libs/go-kibana-rest/kbapi/api.kibana_role_management.go b/libs/go-kibana-rest/kbapi/api.kibana_role_management.go new file mode 100644 index 000000000..897466ac7 --- /dev/null +++ b/libs/go-kibana-rest/kbapi/api.kibana_role_management.go @@ -0,0 +1,190 @@ +package kbapi + +import ( + "encoding/json" + "fmt" + + "github.com/go-resty/resty/v2" + log "github.com/sirupsen/logrus" +) + +const ( + basePathKibanaRoleManagement = "/api/security/role" // Base URL to access on Kibana role management +) + +// KibanaRole is the API role object +type KibanaRole struct { + Name string `json:"name,omitempty"` + Metadata map[string]interface{} `json:"metadata,omitempty"` + TransientMedata *KibanaRoleTransientMetadata `json:"transient_metadata,omitempty"` + Elasticsearch *KibanaRoleElasticsearch `json:"elasticsearch,omitempty"` + Kibana []KibanaRoleKibana `json:"kibana,omitempty"` +} + +// KibanaRoleTransientMetadata is the API TransientMedata object +type KibanaRoleTransientMetadata struct { + Enabled bool `json:"enabled,omitempty"` +} + +// KibanaRoleElasticsearch is the API Elasticsearch object +type KibanaRoleElasticsearch struct { + Indices []KibanaRoleElasticsearchIndice `json:"indices,omitempty"` + Cluster []string `json:"cluster,omitempty"` + RunAs []string `json:"run_as,omitempty"` +} + +// KibanaRoleKibana is the API Kibana object +type KibanaRoleKibana struct { + Base []string `json:"base,omitempty"` + Feature map[string][]string `json:"feature,omitempty"` + Spaces []string `json:"spaces,omitempty"` +} + +// KibanaRoleElasticsearchIndice is the API indice object +type KibanaRoleElasticsearchIndice struct { + Names []string `json:"names,omitempty"` + Privileges []string `json:"privileges,omitempty"` + FieldSecurity map[string]interface{} `json:"field_security,omitempty"` + Query interface{} `json:"query,omitempty"` +} + +// KibanaRoles is a list of role object +type KibanaRoles []KibanaRole + +// KibanaRoleManagementGet permit to get role from Kibana +type KibanaRoleManagementGet func(name string) (*KibanaRole, error) + +// KibanaRoleManagementList permit to get all roles from Kibana +type KibanaRoleManagementList func() (KibanaRoles, error) + +// KibanaRoleManagementCreateOrUpdate permit to create or update role in Kibana +type KibanaRoleManagementCreateOrUpdate func(kibanaRole *KibanaRole) (*KibanaRole, error) + +// KibanaRoleManagementDelete permit to delete role in Kibana +type KibanaRoleManagementDelete func(name string) error + +// String permit to return KibanaRole object as JSON string +func (k *KibanaRole) String() string { + json, _ := json.Marshal(k) + return string(json) +} + +// newKibanaRoleManagementGetFunc permit to get the kibana role with it name +func newKibanaRoleManagementGetFunc(c *resty.Client) KibanaRoleManagementGet { + return func(name string) (*KibanaRole, error) { + + if name == "" { + return nil, NewAPIError(600, "You must provide kibana role name") + } + log.Debug("Name: ", name) + + path := fmt.Sprintf("%s/%s", basePathKibanaRoleManagement, name) + resp, err := c.R().Get(path) + if err != nil { + return nil, err + } + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + if resp.StatusCode() == 404 { + return nil, nil + } + return nil, NewAPIError(resp.StatusCode(), resp.Status()) + } + kibanaRole := &KibanaRole{} + err = json.Unmarshal(resp.Body(), kibanaRole) + if err != nil { + return nil, err + } + log.Debug("KibanaRole: ", kibanaRole) + + return kibanaRole, nil + } + +} + +// newKibanaRoleManagementListFunc permit to get all kibana role +func newKibanaRoleManagementListFunc(c *resty.Client) KibanaRoleManagementList { + return func() (KibanaRoles, error) { + + resp, err := c.R().Get(basePathKibanaRoleManagement) + if err != nil { + return nil, err + } + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + return nil, NewAPIError(resp.StatusCode(), resp.Status()) + } + kibanaRoles := make(KibanaRoles, 0, 1) + err = json.Unmarshal(resp.Body(), &kibanaRoles) + if err != nil { + return nil, err + } + log.Debug("KibanaRoles: ", kibanaRoles) + + return kibanaRoles, nil + } + +} + +// newKibanaRoleManagementGetFunc permit to create or update the kibana role +func newKibanaRoleManagementCreateOrUpdateFunc(c *resty.Client) KibanaRoleManagementCreateOrUpdate { + return func(kibanaRole *KibanaRole) (*KibanaRole, error) { + + if kibanaRole == nil { + return nil, NewAPIError(600, "You must provide kibana role object") + } + log.Debug("Kibana role: ", kibanaRole) + roleName := kibanaRole.Name + + path := fmt.Sprintf("%s/%s", basePathKibanaRoleManagement, roleName) + kibanaRole.Name = "" + jsonData, err := json.Marshal(kibanaRole) + log.Debugf("Payload: %s", jsonData) + if err != nil { + return nil, err + } + resp, err := c.R().SetBody(jsonData).Put(path) + if err != nil { + return nil, err + } + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + return nil, NewAPIError(resp.StatusCode(), resp.Status()) + } + + // Retrive the object to return it + kibanaRole, err = newKibanaRoleManagementGetFunc(c)(roleName) + if err != nil { + return nil, err + } + + log.Debug("KibanaRole: ", kibanaRole) + + return kibanaRole, nil + } + +} + +// newKibanaRoleManagementDeleteFunc permit to delete kibana role with it name +func newKibanaRoleManagementDeleteFunc(c *resty.Client) KibanaRoleManagementDelete { + return func(name string) error { + + if name == "" { + return NewAPIError(600, "You must provide kibana role name") + } + log.Debug("Name: ", name) + + path := fmt.Sprintf("%s/%s", basePathKibanaRoleManagement, name) + resp, err := c.R().Delete(path) + if err != nil { + return err + } + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + return NewAPIError(resp.StatusCode(), resp.Status()) + } + + return nil + } + +} diff --git a/libs/go-kibana-rest/kbapi/api.kibana_role_management_test.go b/libs/go-kibana-rest/kbapi/api.kibana_role_management_test.go new file mode 100644 index 000000000..81c90b582 --- /dev/null +++ b/libs/go-kibana-rest/kbapi/api.kibana_role_management_test.go @@ -0,0 +1,55 @@ +package kbapi + +import ( + "github.com/stretchr/testify/assert" +) + +func (s *KBAPITestSuite) TestKibanaRoleManagement() { + + // Create new role + kibanaRole := &KibanaRole{ + Name: "test", + Elasticsearch: &KibanaRoleElasticsearch{ + Indices: []KibanaRoleElasticsearchIndice{ + { + Names: []string{ + "*", + }, + Privileges: []string{ + "read", + }, + }, + }, + }, + Kibana: []KibanaRoleKibana{ + { + Base: []string{ + "read", + }, + }, + }, + } + kibanaRole, err := s.API.KibanaRoleManagement.CreateOrUpdate(kibanaRole) + assert.NoError(s.T(), err) + assert.NotNil(s.T(), kibanaRole) + assert.Equal(s.T(), "test", kibanaRole.Name) + + // Get role + kibanaRole, err = s.API.KibanaRoleManagement.Get("test") + assert.NoError(s.T(), err) + assert.NotNil(s.T(), kibanaRole) + assert.Equal(s.T(), "test", kibanaRole.Name) + + // List role + kibanaRoles, err := s.API.KibanaRoleManagement.List() + assert.NoError(s.T(), err) + assert.NotEmpty(s.T(), kibanaRoles) + + // Delete role + err = s.API.KibanaRoleManagement.Delete("test") + assert.NoError(s.T(), err) + kibanaRole, err = s.API.KibanaRoleManagement.Get("test") + assert.NoError(s.T(), err) + assert.Nil(s.T(), kibanaRole) + +} diff --git a/libs/go-kibana-rest/kbapi/api.kibana_save_object.go b/libs/go-kibana-rest/kbapi/api.kibana_save_object.go new file mode 100644 index 000000000..a04f18145 --- /dev/null +++ b/libs/go-kibana-rest/kbapi/api.kibana_save_object.go @@ -0,0 +1,411 @@ +package kbapi + +import ( + "bytes" + "encoding/json" + "fmt" + "strconv" + "strings" + + "github.com/go-resty/resty/v2" + log "github.com/sirupsen/logrus" +) + +const ( + basePathKibanaSavedObject = "/api/saved_objects" // Base URL to access on Kibana save objects +) + +// OptionalFindParameters contain optional parameters to find objects +type OptionalFindParameters struct { + ObjectsPerPage int + Page int + Search string + DefaultSearchOperator string + SearchFields []string + Fields []string + SortField string + HasReference string +} + +// KibanaSavedObjectGet permit to get saved object from Kibana +type KibanaSavedObjectGet func(objectType string, id string, kibanaSpace string) (map[string]interface{}, error) + +// KibanaSavedObjectFind permit to find saved objects from Kibana +type KibanaSavedObjectFind func(objectType string, kibanaSpace string, optionalParameters *OptionalFindParameters) (map[string]interface{}, error) + +// KibanaSavedObjectCreate permit to create saved object in Kibana +type KibanaSavedObjectCreate func(data map[string]interface{}, objectType string, id string, overwrite bool, kibanaSpace string) (map[string]interface{}, error) + +// KibanaSavedObjectUpdate permit to update saved object in Kibana +type KibanaSavedObjectUpdate func(data map[string]interface{}, objectType string, id string, kibanaSpace string) (map[string]interface{}, error) + +// KibanaSavedObjectDelete permit to delete saved object in Kibana +type KibanaSavedObjectDelete func(objectType string, id string, kibanaSpace string) error + +// KibanaSavedObjectExport permit to export saved objects from Kibana +type KibanaSavedObjectExport func(objectTypes []string, objects []map[string]string, deepReference bool, kibanaSpace string) ([]byte, error) + +// KibanaSavedObjectImport permit to import saved objects in Kibana +type KibanaSavedObjectImport func(data []byte, overwrite bool, kibanaSpace string) (map[string]interface{}, error) + +// String permit to return OptionalFindParameters object as JSON string +func (o *OptionalFindParameters) String() string { + json, _ := json.Marshal(o) + return string(json) +} + +// newKibanaSavedObjectGetFunc permit to get saved obejct by it id and type +func newKibanaSavedObjectGetFunc(c *resty.Client) KibanaSavedObjectGet { + return func(objectType string, id string, kibanaSpace string) (map[string]interface{}, error) { + + if objectType == "" { + return nil, NewAPIError(600, "You must provide the object type") + } + if id == "" { + return nil, NewAPIError(600, "You must provide the object ID") + } + log.Debug("ObjectType: ", objectType) + log.Debug("ID: ", id) + log.Debug("KibanaSpace: ", kibanaSpace) + + var path string + if kibanaSpace == "" || kibanaSpace == "default" { + path = fmt.Sprintf("%s/%s/%s", basePathKibanaSavedObject, objectType, id) + } else { + path = fmt.Sprintf("/s/%s%s/%s/%s", kibanaSpace, basePathKibanaSavedObject, objectType, id) + } + log.Debugf("URL to get object: %s", path) + + resp, err := c.R().Get(path) + if err != nil { + return nil, err + } + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + if resp.StatusCode() == 404 { + return nil, nil + } + return nil, NewAPIError(resp.StatusCode(), resp.Status()) + + } + var data map[string]interface{} + err = json.Unmarshal(resp.Body(), &data) + if err != nil { + return nil, err + } + log.Debug("Data: ", data) + + return data, nil + } + +} + +// newKibanaSavedObjectFindFunc permit to search objects +func newKibanaSavedObjectFindFunc(c *resty.Client) KibanaSavedObjectFind { + return func(objectType string, kibanaSpace string, optionalParameters *OptionalFindParameters) (map[string]interface{}, error) { + + if objectType == "" { + return nil, NewAPIError(600, "You must provide the object type") + } + log.Debug("ObjectType: ", objectType) + log.Debug("KibanaSpace : ", kibanaSpace) + + queryParams := map[string]string{ + "type": objectType, + } + if optionalParameters != nil { + log.Debug("Objects Per Page: ", optionalParameters.ObjectsPerPage) + log.Debug("Page: ", optionalParameters.Page) + log.Debug("Search: ", optionalParameters.Search) + log.Debug("DefaultSearchOperator: ", optionalParameters.DefaultSearchOperator) + log.Debug("SearchFields: ", optionalParameters.SearchFields) + log.Debug("Fields: ", optionalParameters.Fields) + log.Debug("SortField: ", optionalParameters.SortField) + log.Debug("HasReference: ", optionalParameters.HasReference) + if optionalParameters.ObjectsPerPage != 0 { + queryParams["per_page"] = strconv.Itoa(optionalParameters.ObjectsPerPage) + } + if optionalParameters.Page != 0 { + queryParams["page"] = strconv.Itoa(optionalParameters.Page) + } + if optionalParameters.Search != "" { + queryParams["search"] = optionalParameters.Search + } + if optionalParameters.DefaultSearchOperator != "" { + queryParams["default_search_operator"] = optionalParameters.DefaultSearchOperator + } + if optionalParameters.SearchFields != nil { + queryParams["search_fields"] = strings.Join(optionalParameters.SearchFields, ",") + } + if optionalParameters.Fields != nil { + queryParams["fields"] = strings.Join(optionalParameters.Fields, ",") + } + if optionalParameters.SortField != "" { + queryParams["sort_field"] = optionalParameters.SortField + } + if optionalParameters.HasReference != "" { + queryParams["has_reference"] = optionalParameters.HasReference + } + } + + var path string + if kibanaSpace == "" || kibanaSpace == "default" { + path = fmt.Sprintf("%s/_find", basePathKibanaSavedObject) + } else { + path = fmt.Sprintf("/s/%s%s/_find", kibanaSpace, basePathKibanaSavedObject) + } + log.Debugf("URL to find object: %s", path) + + resp, err := c.R().SetQueryParams(queryParams).Get(path) + if err != nil { + return nil, err + } + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + if resp.StatusCode() == 404 { + return nil, nil + } + return nil, NewAPIError(resp.StatusCode(), resp.Status()) + + } + var data map[string]interface{} + err = json.Unmarshal(resp.Body(), &data) + if err != nil { + return nil, err + } + log.Debug("Data: ", data) + + return data, nil + } + +} + +// newKibanaSavedObjectCreateFunc permit to create new object on Kibana +func newKibanaSavedObjectCreateFunc(c *resty.Client) KibanaSavedObjectCreate { + return func(data map[string]interface{}, objectType string, id string, overwrite bool, kibanaSpace string) (map[string]interface{}, error) { + + if data == nil { + return nil, NewAPIError(600, "You must provide one or more dashboard to import") + } + if objectType == "" { + return nil, NewAPIError(600, "You must provide the object type") + } + log.Debug("data: ", data) + log.Debug("ObjectType: ", objectType) + log.Debug("ID: ", id) + log.Debug("Overwrite: ", overwrite) + log.Debug("KibanaSpace: ", kibanaSpace) + + var path string + if kibanaSpace == "" || kibanaSpace == "default" { + path = fmt.Sprintf("%s/%s/%s", basePathKibanaSavedObject, objectType, id) + } else { + path = fmt.Sprintf("/s/%s%s/%s/%s", kibanaSpace, basePathKibanaSavedObject, objectType, id) + } + log.Debugf("URL to create object: %s", path) + + jsonData, err := json.Marshal(data) + if err != nil { + return nil, err + } + resp, err := c.R().SetQueryString(fmt.Sprintf("overwrite=%t", overwrite)).SetBody(jsonData).Post(path) + if err != nil { + return nil, err + } + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + return nil, NewAPIError(resp.StatusCode(), resp.Status()) + } + var dataResponse map[string]interface{} + err = json.Unmarshal(resp.Body(), &dataResponse) + if err != nil { + return nil, err + } + log.Debug("Data response: ", dataResponse) + + return dataResponse, nil + } +} + +// newKibanaSavedObjectUpdateFunc permit to update object on Kibana +func newKibanaSavedObjectUpdateFunc(c *resty.Client) KibanaSavedObjectUpdate { + return func(data map[string]interface{}, objectType string, id string, kibanaSpace string) (map[string]interface{}, error) { + + if data == nil { + return nil, NewAPIError(600, "You must provide one or more dashboard to import") + } + if objectType == "" { + return nil, NewAPIError(600, "You must provide the object type") + } + if id == "" { + return nil, NewAPIError(600, "You must provide the ID") + } + log.Debug("data: ", data) + log.Debug("ObjectType: ", objectType) + log.Debug("ID: ", id) + log.Debug("kibanaSpace: ", kibanaSpace) + + var path string + if kibanaSpace == "" || kibanaSpace == "default" { + path = fmt.Sprintf("%s/%s/%s", basePathKibanaSavedObject, objectType, id) + } else { + path = fmt.Sprintf("/s/%s%s/%s/%s", kibanaSpace, basePathKibanaSavedObject, objectType, id) + } + log.Debugf("URL to update object: %s", path) + + jsonData, err := json.Marshal(data) + if err != nil { + return nil, err + } + resp, err := c.R().SetBody(jsonData).Put(path) + if err != nil { + return nil, err + } + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + return nil, NewAPIError(resp.StatusCode(), resp.Status()) + } + var dataResponse map[string]interface{} + err = json.Unmarshal(resp.Body(), &dataResponse) + if err != nil { + return nil, err + } + log.Debug("Data response: ", dataResponse) + + return dataResponse, nil + } +} + +// newKibanaSavedObjectDeleteFunc permit to delete object on Kibana +func newKibanaSavedObjectDeleteFunc(c *resty.Client) KibanaSavedObjectDelete { + return func(objectType string, id string, kibanaSpace string) error { + + if objectType == "" { + return NewAPIError(600, "You must provide the object type") + } + if id == "" { + return NewAPIError(600, "You must provide the id") + } + log.Debug("objectType: ", objectType) + log.Debug("ID: ", id) + log.Debug("KibanaSpace: ", kibanaSpace) + + var path string + if kibanaSpace == "" || kibanaSpace == "default" { + path = fmt.Sprintf("%s/%s/%s", basePathKibanaSavedObject, objectType, id) + } else { + path = fmt.Sprintf("/s/%s%s/%s/%s", kibanaSpace, basePathKibanaSavedObject, objectType, id) + } + log.Debugf("URL to delete object: %s", path) + + resp, err := c.R().Delete(path) + if err != nil { + return err + } + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + return NewAPIError(resp.StatusCode(), resp.Status()) + } + var dataResponse map[string]interface{} + err = json.Unmarshal(resp.Body(), &dataResponse) + if err != nil { + return err + } + log.Debug("Data response: ", dataResponse) + + return nil + } +} + +// newKibanaSavedObjectExportFunc permit to export Kibana object +func newKibanaSavedObjectExportFunc(c *resty.Client) KibanaSavedObjectExport { + return func(objectTypes []string, objects []map[string]string, deepReference bool, kibanaSpace string) ([]byte, error) { + + log.Debug("ObjectTypes: ", objectTypes) + log.Debug("Objects: ", objects) + log.Debug("DeepReference: ", deepReference) + log.Debug("KibanaSpace: ", kibanaSpace) + + payload := make(map[string]interface{}) + payload["excludeExportDetails"] = true + + if len(objectTypes) > 0 { + payload["type"] = objectTypes + } + if len(objects) > 0 { + payload["objects"] = objects + } + payload["includeReferencesDeep"] = deepReference + log.Debug("Payload: ", payload) + + var path string + if kibanaSpace == "" || kibanaSpace == "default" { + path = fmt.Sprintf("%s/_export", basePathKibanaSavedObject) + } else { + path = fmt.Sprintf("/s/%s%s/_export", kibanaSpace, basePathKibanaSavedObject) + } + log.Debugf("URL to export object: %s", path) + + jsonData, err := json.Marshal(payload) + if err != nil { + return nil, err + } + resp, err := c.R().SetBody(jsonData).Post(path) + if err != nil { + return nil, err + } + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + return nil, NewAPIError(resp.StatusCode(), resp.Status()) + } + + data := resp.Body() + log.Debug("Data response: ", data) + + return data, nil + + } +} + +// newKibanaSavedObjectImportFunc permit to import Kibana object +func newKibanaSavedObjectImportFunc(c *resty.Client) KibanaSavedObjectImport { + return func(data []byte, overwrite bool, kibanaSpace string) (map[string]interface{}, error) { + + if len(data) == 0 { + return nil, NewAPIError(600, "You must provide data parameters") + } + + log.Debug("Data: ", data) + log.Debug("Overwrite: ", overwrite) + log.Debug("kibanaSpace: ", kibanaSpace) + + var path string + if kibanaSpace == "" || kibanaSpace == "default" { + path = fmt.Sprintf("%s/_import", basePathKibanaSavedObject) + } else { + path = fmt.Sprintf("/s/%s%s/_import", kibanaSpace, basePathKibanaSavedObject) + } + log.Debugf("URL to export object: %s", path) + + resp, err := c.R(). + SetQueryString(fmt.Sprintf("overwrite=%t", overwrite)). + SetFileReader("file", "file.ndjson", bytes.NewReader(data)). + Post(path) + if err != nil { + return nil, err + } + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + return nil, NewAPIError(resp.StatusCode(), resp.Status()) + } + var dataResponse map[string]interface{} + err = json.Unmarshal(resp.Body(), &dataResponse) + if err != nil { + return nil, err + } + log.Debug("Data response: ", dataResponse) + + return dataResponse, nil + + } +} diff --git a/libs/go-kibana-rest/kbapi/api.kibana_save_object_test.go b/libs/go-kibana-rest/kbapi/api.kibana_save_object_test.go new file mode 100644 index 000000000..988d91ba7 --- /dev/null +++ b/libs/go-kibana-rest/kbapi/api.kibana_save_object_test.go @@ -0,0 +1,152 @@ +package kbapi + +import ( + "encoding/json" + + "github.com/stretchr/testify/assert" +) + +func (s *KBAPITestSuite) TestKibanaSaveObject() { + + // Create new index pattern + dataJSON := `{"attributes": {"title": "test-pattern-*"}}` + data := make(map[string]interface{}) + err := json.Unmarshal([]byte(dataJSON), &data) + if err != nil { + panic(err) + } + resp, err := s.API.KibanaSavedObject.Create(data, "index-pattern", "test", true, "default") + assert.NoError(s.T(), err) + assert.NotNil(s.T(), resp) + assert.Equal(s.T(), "test", resp["id"]) + assert.Equal(s.T(), "test-pattern-*", resp["attributes"].(map[string]interface{})["title"]) + + // Create new index pattern in space + dataJSON = `{"attributes": {"title": "test-pattern-*"}}` + data = make(map[string]interface{}) + err = json.Unmarshal([]byte(dataJSON), &data) + if err != nil { + panic(err) + } + resp, err = s.API.KibanaSavedObject.Create(data, "index-pattern", "test2", true, "testacc") + assert.NoError(s.T(), err) + assert.NotNil(s.T(), resp) + assert.Equal(s.T(), "test2", resp["id"]) + assert.Equal(s.T(), "test-pattern-*", resp["attributes"].(map[string]interface{})["title"]) + + // Get index pattern + resp, err = s.API.KibanaSavedObject.Get("index-pattern", "test", "default") + assert.NoError(s.T(), err) + assert.NotNil(s.T(), resp) + assert.Equal(s.T(), "test", resp["id"]) + + // Get index pattern from space + resp, err = s.API.KibanaSavedObject.Get("index-pattern", "test2", "testacc") + assert.NoError(s.T(), err) + assert.NotNil(s.T(), resp) + assert.Equal(s.T(), "test2", resp["id"]) + + // Search index pattern + parameters := &OptionalFindParameters{ + Search: "test*", + SearchFields: []string{"title"}, + Fields: []string{"id"}, + } + resp, err = s.API.KibanaSavedObject.Find("index-pattern", "default", parameters) + assert.NoError(s.T(), err) + assert.NotNil(s.T(), resp) + dataRes := resp["saved_objects"].([]interface{})[0].(map[string]interface{}) + assert.NotEmpty(s.T(), dataRes["id"].(string)) + + // Search index pattern from space + parameters = &OptionalFindParameters{ + Search: "test*", + SearchFields: []string{"title"}, + Fields: []string{"id"}, + } + resp, err = s.API.KibanaSavedObject.Find("index-pattern", "testacc", parameters) + assert.NoError(s.T(), err) + assert.NotNil(s.T(), resp) + dataRes = resp["saved_objects"].([]interface{})[0].(map[string]interface{}) + assert.NotEmpty(s.T(), dataRes["id"].(string)) + + // Update index pattern + dataJSON = `{"attributes": {"title": "test-pattern2-*"}}` + err = json.Unmarshal([]byte(dataJSON), &data) + if err != nil { + panic(err) + } + resp, err = s.API.KibanaSavedObject.Update(data, "index-pattern", "test", "default") + assert.NoError(s.T(), err) + assert.NotNil(s.T(), resp) + assert.Equal(s.T(), "test", resp["id"]) + assert.Equal(s.T(), "test-pattern2-*", resp["attributes"].(map[string]interface{})["title"]) + + // Update index pattern in space + dataJSON = `{"attributes": {"title": "test-pattern2-*"}}` + err = json.Unmarshal([]byte(dataJSON), &data) + if err != nil { + panic(err) + } + resp, err = s.API.KibanaSavedObject.Update(data, "index-pattern", "test2", "testacc") + assert.NoError(s.T(), err) + assert.NotNil(s.T(), resp) + assert.Equal(s.T(), "test2", resp["id"]) + assert.Equal(s.T(), "test-pattern2-*", resp["attributes"].(map[string]interface{})["title"]) + + // Export index pattern + request := []map[string]string{ + { + "type": "index-pattern", + "id": "test", + }, + } + dataExported, err := s.API.KibanaSavedObject.Export(nil, request, true, "default") + assert.NoError(s.T(), err) + assert.NotEmpty(s.T(), dataExported) + + // Export index pattern from space + request = []map[string]string{ + { + "type": "index-pattern", + "id": "test2", + }, + } + dataExported, err = s.API.KibanaSavedObject.Export(nil, request, true, "testacc") + assert.NoError(s.T(), err) + assert.NotEmpty(s.T(), dataExported) + + // import index pattern + b, err := json.Marshal(resp) + if err != nil { + panic(err) + } + resp2, err := s.API.KibanaSavedObject.Import(b, true, "default") + assert.NoError(s.T(), err) + assert.NotNil(s.T(), resp2) + assert.Equal(s.T(), true, resp2["success"]) + + // import index pattern in space + b, err = json.Marshal(resp) + if err != nil { + panic(err) + } + resp, err = s.API.KibanaSavedObject.Import(b, true, "testacc") + assert.NoError(s.T(), err) + assert.NotNil(s.T(), resp) + assert.Equal(s.T(), true, resp["success"]) + + // Delete index pattern + err = s.API.KibanaSavedObject.Delete("index-pattern", "test", "default") + assert.NoError(s.T(), err) + resp, err = s.API.KibanaSavedObject.Get("index-pattern", "test", "default") + assert.NoError(s.T(), err) + assert.Nil(s.T(), resp) + + // Delete index pattern in space + err = s.API.KibanaSavedObject.Delete("index-pattern", "test2", "testacc") + assert.NoError(s.T(), err) + resp, err = s.API.KibanaSavedObject.Get("index-pattern", "test2", "testacc") + assert.NoError(s.T(), err) + assert.Nil(s.T(), resp) +} diff --git a/libs/go-kibana-rest/kbapi/api.kibana_shorten_url.go b/libs/go-kibana-rest/kbapi/api.kibana_shorten_url.go new file mode 100644 index 000000000..257d9bb44 --- /dev/null +++ b/libs/go-kibana-rest/kbapi/api.kibana_shorten_url.go @@ -0,0 +1,78 @@ +package kbapi + +import ( + "encoding/json" + + "github.com/go-resty/resty/v2" + log "github.com/sirupsen/logrus" +) + +const ( + basePathKibanaShortenURL = "/api/short_url" // Base URL to access on Kibana shorten URL +) + +// ShortenURL is the shorten URL object +type ShortenURL struct { + LocatorId string `json:"locatorId"` + Params map[string]any `json:"params"` + Slug string `json:"slug,omitempty"` + HumanReadableSlug bool `json:"humanReadableSlug,omitempty"` +} + +// ShortenURLResponse is the shorten URL object response +type ShortenURLResponse struct { + ID string `json:"id"` + Locator *ShortenURL `json:"locator"` +} + +// KibanaShortenURLCreate permit to create new shorten URL +type KibanaShortenURLCreate func(shortenURL *ShortenURL) (*ShortenURLResponse, error) + +// String permit to return ShortenURL object as JSON string +func (o *ShortenURL) String() string { + json, _ := json.Marshal(o) + return string(json) +} + +// String permit to return ShortenURLResponse object as JSON string +func (o *ShortenURLResponse) String() string { + json, _ := json.Marshal(o) + return string(json) +} + +// newKibanaShortenURLCreateFunc permit to create new shorten URL +func newKibanaShortenURLCreateFunc(c *resty.Client) KibanaShortenURLCreate { + return func(shortenURL *ShortenURL) (*ShortenURLResponse, error) { + + if shortenURL == nil { + return nil, NewAPIError(600, "You must provide shorten URL object") + } + log.Debug("Shorten URL: ", shortenURL) + + jsonData, err := json.Marshal(shortenURL) + if err != nil { + return nil, err + } + + log.Debugf("Shorten URL payload: %s", jsonData) + + resp, err := c.R().SetBody(jsonData).Post(basePathKibanaShortenURL) + if err != nil { + return nil, err + } + + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + return nil, NewAPIError(resp.StatusCode(), resp.Status()) + } + + shortenURLResponse := &ShortenURLResponse{} + err = json.Unmarshal(resp.Body(), shortenURLResponse) + if err != nil { + return nil, err + } + log.Debug("ShortenURLResponse: ", shortenURLResponse) + + return shortenURLResponse, nil + } +} diff --git a/libs/go-kibana-rest/kbapi/api.kibana_shorten_url_test.go b/libs/go-kibana-rest/kbapi/api.kibana_shorten_url_test.go new file mode 100644 index 000000000..ca9e21fc9 --- /dev/null +++ b/libs/go-kibana-rest/kbapi/api.kibana_shorten_url_test.go @@ -0,0 +1,20 @@ +package kbapi + +import ( + "github.com/stretchr/testify/assert" +) + +func (s *KBAPITestSuite) TestKibanaShortenURL() { + + // Create new shorten URL + shortenURL := &ShortenURL{ + LocatorId: "LEGACY_SHORT_URL_LOCATOR", + Params: map[string]any{ + "url": "/app/kibana#/dashboard?_g=()&_a=(description:'',filters:!(),fullScreenMode:!f,options:(hidePanelTitles:!f,useMargins:!t),panels:!((embeddableConfig:(),gridData:(h:15,i:'1',w:24,x:0,y:0),id:'8f4d0c00-4c86-11e8-b3d7-01146121b73d',panelIndex:'1',type:visualization,version:'7.0.0-alpha1')),query:(language:lucene,query:''),timeRestore:!f,title:'New%20Dashboard',viewMode:edit)", + }, + } + shortenURLResponse, err := s.API.KibanaShortenURL.Create(shortenURL) + assert.NoError(s.T(), err) + assert.NotNil(s.T(), shortenURLResponse) + assert.NotEmpty(s.T(), shortenURLResponse.ID) +} diff --git a/libs/go-kibana-rest/kbapi/api.kibana_spaces.go b/libs/go-kibana-rest/kbapi/api.kibana_spaces.go new file mode 100644 index 000000000..12e581b65 --- /dev/null +++ b/libs/go-kibana-rest/kbapi/api.kibana_spaces.go @@ -0,0 +1,274 @@ +package kbapi + +import ( + "encoding/json" + "fmt" + "strings" + + "github.com/go-resty/resty/v2" + log "github.com/sirupsen/logrus" +) + +const ( + basePathKibanaSpace = "/api/spaces" // Base URL to access on Kibana space API +) + +// KibanaSpace is the Space API object +type KibanaSpace struct { + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description,omitempty"` + DisabledFeatures []string `json:"disabledFeatures,omitempty"` + Reserved bool `json:"_reserved,omitempty"` + Initials string `json:"initials,omitempty"` + Color string `json:"color,omitempty"` +} + +// KibanaSpaces is the list of KibanaSpace object +type KibanaSpaces []KibanaSpace + +// KibanaSpaceCopySavedObjectParameter is parameters to copy dashboard between spaces +type KibanaSpaceCopySavedObjectParameter struct { + Spaces []string `json:"spaces"` + IncludeReferences bool `json:"includeReferences"` + Overwrite bool `json:"overwrite"` + CreateNewCopies bool `json:"createNewCopies"` + Objects []KibanaSpaceObjectParameter `json:"objects"` +} + +// KibanaSpaceObjectParameter is Object object +type KibanaSpaceObjectParameter struct { + Type string `json:"type"` + ID string `json:"id"` +} + +// KibanaSpaceGet permit to get space +type KibanaSpaceGet func(id string) (*KibanaSpace, error) + +// KibanaSpaceList permit to get all spaces +type KibanaSpaceList func() (KibanaSpaces, error) + +// KibanaSpaceCreate permit to create space +type KibanaSpaceCreate func(kibanaSpace *KibanaSpace) (*KibanaSpace, error) + +// KibanaSpaceDelete permit to delete space +type KibanaSpaceDelete func(id string) error + +// KibanaSpaceUpdate permit to update space +type KibanaSpaceUpdate func(kibanaSpace *KibanaSpace) (*KibanaSpace, error) + +// KibanaSpaceCopySavedObjects permit to copy dashboad between space +type KibanaSpaceCopySavedObjects func(parameter *KibanaSpaceCopySavedObjectParameter, spaceOrigin string) error + +// String permit to return KibanaSpace object as JSON string +func (k *KibanaSpace) String() string { + json, _ := json.Marshal(k) + return string(json) +} + +// newKibanaSpaceGetFunc permit to get the kibana space with it id +func newKibanaSpaceGetFunc(c *resty.Client) KibanaSpaceGet { + return func(id string) (*KibanaSpace, error) { + + if id == "" { + return nil, NewAPIError(600, "You must provide kibana space ID") + } + log.Debug("ID: ", id) + + path := fmt.Sprintf("%s/space/%s", basePathKibanaSpace, id) + resp, err := c.R().Get(path) + if err != nil { + return nil, err + } + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + if resp.StatusCode() == 404 { + return nil, nil + } + return nil, NewAPIError(resp.StatusCode(), resp.Status()) + + } + kibanaSpace := &KibanaSpace{} + err = json.Unmarshal(resp.Body(), kibanaSpace) + if err != nil { + return nil, err + } + log.Debug("KibanaSpace: ", kibanaSpace) + + return kibanaSpace, nil + } + +} + +// newKibanaSpaceListFunc permit to get all Kibana space +func newKibanaSpaceListFunc(c *resty.Client) KibanaSpaceList { + return func() (KibanaSpaces, error) { + + path := fmt.Sprintf("%s/space", basePathKibanaSpace) + resp, err := c.R().Get(path) + if err != nil { + return nil, err + } + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + return nil, NewAPIError(resp.StatusCode(), resp.Status()) + } + kibanaSpaces := make(KibanaSpaces, 0, 1) + err = json.Unmarshal(resp.Body(), &kibanaSpaces) + if err != nil { + return nil, err + } + log.Debug("KibanaSpaces: ", kibanaSpaces) + + return kibanaSpaces, nil + } + +} + +// newKibanaSpaceCreateFunc permit to create new Kibana space +func newKibanaSpaceCreateFunc(c *resty.Client) KibanaSpaceCreate { + return func(kibanaSpace *KibanaSpace) (*KibanaSpace, error) { + + if kibanaSpace == nil { + return nil, NewAPIError(600, "You must provide kibana space object") + } + log.Debug("KibanaSpace: ", kibanaSpace) + + jsonData, err := json.Marshal(kibanaSpace) + if err != nil { + return nil, err + } + path := fmt.Sprintf("%s/space", basePathKibanaSpace) + resp, err := c.R().SetBody(jsonData).Post(path) + if err != nil { + return nil, err + } + + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + return nil, NewAPIError(resp.StatusCode(), resp.Status()) + } + kibanaSpace = &KibanaSpace{} + err = json.Unmarshal(resp.Body(), kibanaSpace) + if err != nil { + return nil, err + } + log.Debug("KibanaSpace: ", kibanaSpace) + + return kibanaSpace, nil + } + +} + +// newKibanaSpaceCopySavedObjectsFunc permit to copy extings objects from user space to another userSpace +func newKibanaSpaceCopySavedObjectsFunc(c *resty.Client) KibanaSpaceCopySavedObjects { + return func(parameter *KibanaSpaceCopySavedObjectParameter, spaceOrigin string) error { + + if parameter == nil { + return NewAPIError(600, "You must provide parameter to copy existing objects on other user spaces") + } + log.Debug("Parameter: ", parameter) + log.Debug("SpaceOrigin: ", spaceOrigin) + + var path string + if spaceOrigin == "" || spaceOrigin == "default" { + path = fmt.Sprintf("%s/_copy_saved_objects", basePathKibanaSpace) + } else { + path = fmt.Sprintf("/s/%s%s/_copy_saved_objects", spaceOrigin, basePathKibanaSpace) + } + jsonData, err := json.Marshal(parameter) + if err != nil { + return err + } + resp, err := c.R().SetBody(jsonData).Post(path) + if err != nil { + return err + } + + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + return NewAPIError(resp.StatusCode(), resp.Status()) + } + data := make(map[string]interface{}) + err = json.Unmarshal(resp.Body(), &data) + if err != nil { + return err + } + log.Debug("Response: ", data) + + var errors []string + for name, object := range data { + if !object.(map[string]interface{})["success"].(bool) { + errors = append(errors, fmt.Sprintf("Error to process user space %s", name)) + } + } + if len(errors) > 0 { + return NewAPIError(500, strings.Join(errors, "\n")) + } + + return nil + } + +} + +// newKibanaSpaceDeleteFunc permit to delete the kubana space wiht it id +func newKibanaSpaceDeleteFunc(c *resty.Client) KibanaSpaceDelete { + return func(id string) error { + + if id == "" { + return NewAPIError(600, "You must provide kibana space ID") + } + + log.Debug("ID: ", id) + + path := fmt.Sprintf("%s/space/%s", basePathKibanaSpace, id) + resp, err := c.R().Delete(path) + if err != nil { + return err + } + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + + return NewAPIError(resp.StatusCode(), resp.Status()) + + } + + return nil + } + +} + +// newKibanaSpaceUpdateFunc permit to update the Kibana space +func newKibanaSpaceUpdateFunc(c *resty.Client) KibanaSpaceUpdate { + return func(kibanaSpace *KibanaSpace) (*KibanaSpace, error) { + + if kibanaSpace == nil { + return nil, NewAPIError(600, "You must provide kibana space object") + } + log.Debug("KibanaSpace: ", kibanaSpace) + + jsonData, err := json.Marshal(kibanaSpace) + if err != nil { + return nil, err + } + path := fmt.Sprintf("%s/space/%s", basePathKibanaSpace, kibanaSpace.ID) + resp, err := c.R().SetBody(jsonData).Put(path) + if err != nil { + return nil, err + } + + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + return nil, NewAPIError(resp.StatusCode(), resp.Status()) + } + kibanaSpace = &KibanaSpace{} + err = json.Unmarshal(resp.Body(), kibanaSpace) + if err != nil { + return nil, err + } + log.Debug("KibanaSpace: ", kibanaSpace) + + return kibanaSpace, nil + } + +} diff --git a/libs/go-kibana-rest/kbapi/api.kibana_spaces_test.go b/libs/go-kibana-rest/kbapi/api.kibana_spaces_test.go new file mode 100644 index 000000000..09cd72d9d --- /dev/null +++ b/libs/go-kibana-rest/kbapi/api.kibana_spaces_test.go @@ -0,0 +1,59 @@ +package kbapi + +import ( + "github.com/stretchr/testify/assert" +) + +func (s *KBAPITestSuite) TestKibanaSpaces() { + + // List kibana space + kibanaSpaces, err := s.API.KibanaSpaces.List() + assert.NoError(s.T(), err) + assert.NotEmpty(s.T(), kibanaSpaces) + + // Get the default Space + kibanaSpace, err := s.API.KibanaSpaces.Get(kibanaSpaces[0].ID) + assert.NoError(s.T(), err) + assert.Equal(s.T(), kibanaSpaces[0].ID, kibanaSpace.ID) + assert.Equal(s.T(), "Default", kibanaSpace.Name) + + // Create new space + kibanaSpace = &KibanaSpace{ + ID: "test", + Name: "test", + Description: "My test", + } + kibanaSpace, err = s.KibanaSpaces.Create(kibanaSpace) + assert.NoError(s.T(), err) + assert.NotEmpty(s.T(), kibanaSpace.ID) + + // Update space + kibanaSpace.Name = "test2" + kibanaSpace, err = s.KibanaSpaces.Update(kibanaSpace) + assert.NoError(s.T(), err) + assert.Equal(s.T(), "test2", kibanaSpace.Name) + + // Copy object on space + parameter := &KibanaSpaceCopySavedObjectParameter{ + Spaces: []string{"test"}, + IncludeReferences: true, + Overwrite: false, + CreateNewCopies: true, + Objects: []KibanaSpaceObjectParameter{ + { + Type: "config", + ID: "8.5.0", + }, + }, + } + err = s.KibanaSpaces.CopySavedObjects(parameter, "") + assert.NoError(s.T(), err) + + // Delete space + err = s.KibanaSpaces.Delete(kibanaSpace.ID) + assert.NoError(s.T(), err) + kibanaSpace, err = s.KibanaSpaces.Get(kibanaSpace.ID) + assert.NoError(s.T(), err) + assert.Nil(s.T(), kibanaSpace) + +} diff --git a/libs/go-kibana-rest/kbapi/api.kibana_status.go b/libs/go-kibana-rest/kbapi/api.kibana_status.go new file mode 100644 index 000000000..c6ad95539 --- /dev/null +++ b/libs/go-kibana-rest/kbapi/api.kibana_status.go @@ -0,0 +1,43 @@ +package kbapi + +import ( + "encoding/json" + + "github.com/go-resty/resty/v2" + log "github.com/sirupsen/logrus" +) + +const ( + basePathKibanaStatus = "/api/status" // Base URL to access on Kibana status +) + +// KibanaStatus is the map of string that contain the API status +type KibanaStatus map[string]interface{} + +// KibanaStatusGet permit to get the current status of Kibana +type KibanaStatusGet func() (KibanaStatus, error) + +// newKibanaStatusGetFunc permit to get the kibana status and some usefull information +func newKibanaStatusGetFunc(c *resty.Client) KibanaStatusGet { + return func() (KibanaStatus, error) { + resp, err := c.R().Get(basePathKibanaStatus) + if err != nil { + return nil, err + } + log.Debug("Response: ", resp) + if resp.StatusCode() >= 300 { + if resp.StatusCode() == 404 { + return nil, nil + } + return nil, NewAPIError(resp.StatusCode(), resp.Status()) + } + kibanaStatus := make(KibanaStatus) + err = json.Unmarshal(resp.Body(), &kibanaStatus) + if err != nil { + return nil, err + } + log.Debug("KibanaStatus: ", kibanaStatus) + + return kibanaStatus, nil + } +} diff --git a/libs/go-kibana-rest/kbapi/api.kibana_status_test.go b/libs/go-kibana-rest/kbapi/api.kibana_status_test.go new file mode 100644 index 000000000..d67bb7cc9 --- /dev/null +++ b/libs/go-kibana-rest/kbapi/api.kibana_status_test.go @@ -0,0 +1,13 @@ +package kbapi + +import ( + "github.com/stretchr/testify/assert" +) + +func (s *KBAPITestSuite) TestKibanaStatus() { + + // List kibana space + kibanaStatus, err := s.API.KibanaStatus.Get() + assert.NoError(s.T(), err) + assert.NotEmpty(s.T(), kibanaStatus) +} diff --git a/libs/go-kibana-rest/kbapi/api_test.go b/libs/go-kibana-rest/kbapi/api_test.go new file mode 100644 index 000000000..6dbe3eba5 --- /dev/null +++ b/libs/go-kibana-rest/kbapi/api_test.go @@ -0,0 +1,82 @@ +package kbapi + +import ( + "fmt" + "os" + "testing" + "time" + + "github.com/go-resty/resty/v2" + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/suite" + prefixed "github.com/x-cray/logrus-prefixed-formatter" +) + +type KBAPITestSuite struct { + suite.Suite + client *resty.Client + *API +} + +func (s *KBAPITestSuite) SetupSuite() { + + // Init logger + logrus.SetFormatter(new(prefixed.TextFormatter)) + logrus.SetLevel(logrus.DebugLevel) + + address := os.Getenv("KIBANA_URL") + username := os.Getenv("KIBANA_USERNAME") + password := os.Getenv("KIBANA_PASSWORD") + + if address == "" { + panic("You need to put kibana url on environment variable KIBANA_URL. If you need auth, you can use KIBANA_USERNAME and KIBANA_PASSWORD") + } + + restyClient := resty.New(). + SetBaseURL(address). + SetBasicAuth(username, password). + SetHeader("kbn-xsrf", "true"). + SetHeader("Content-Type", "application/json") + + s.client = restyClient + s.API = New(restyClient) + + // Wait kb is online + isOnline := false + nbTry := 0 + for isOnline == false { + _, err := s.API.KibanaSpaces.List() + if err == nil { + isOnline = true + } else { + time.Sleep(5 * time.Second) + if nbTry == 10 { + panic(fmt.Sprintf("We wait 50s that Kibana start: %s", err)) + } + nbTry++ + } + } + + // Create kibana space + space := &KibanaSpace{ + ID: "testacc", + Name: "testacc", + } + _, err := s.API.KibanaSpaces.Create(space) + if err != nil { + if err.(APIError).Code != 409 { + panic(err) + } + } + +} + +func (s *KBAPITestSuite) SetupTest() { + + // Do somethink before each test + +} + +func TestKBAPITestSuite(t *testing.T) { + suite.Run(t, new(KBAPITestSuite)) +} diff --git a/libs/go-kibana-rest/kbapi/doc.go b/libs/go-kibana-rest/kbapi/doc.go new file mode 100644 index 000000000..40e821754 --- /dev/null +++ b/libs/go-kibana-rest/kbapi/doc.go @@ -0,0 +1,4 @@ +/* +Package kbapi provides the GO API for Kibana +*/ +package kbapi diff --git a/libs/go-kibana-rest/kbapi/error.go b/libs/go-kibana-rest/kbapi/error.go new file mode 100644 index 000000000..1f918bbcd --- /dev/null +++ b/libs/go-kibana-rest/kbapi/error.go @@ -0,0 +1,24 @@ +package kbapi + +import ( + "fmt" +) + +// APIError is the error object +type APIError struct { + Code int + Message string +} + +// Error return error message +func (e APIError) Error() string { + return e.Message +} + +// NewAPIError create new API error with code and message +func NewAPIError(code int, message string, params ...interface{}) APIError { + return APIError{ + Code: code, + Message: fmt.Sprintf(message, params...), + } +} diff --git a/libs/go-kibana-rest/kbapi/error_test.go b/libs/go-kibana-rest/kbapi/error_test.go new file mode 100644 index 000000000..49852a8d4 --- /dev/null +++ b/libs/go-kibana-rest/kbapi/error_test.go @@ -0,0 +1,10 @@ +package kbapi + +import "github.com/stretchr/testify/assert" + +func (s *KBAPITestSuite) TestError() { + + err := NewAPIError(404, "test %s error", "plop") + assert.Equal(s.T(), 404, err.Code) + assert.Equal(s.T(), "test plop error", err.Error()) +} diff --git a/libs/go-kibana-rest/kibana.go b/libs/go-kibana-rest/kibana.go new file mode 100644 index 000000000..560820a4b --- /dev/null +++ b/libs/go-kibana-rest/kibana.go @@ -0,0 +1,63 @@ +package kibana + +import ( + "crypto/tls" + + "github.com/disaster37/go-kibana-rest/v8/kbapi" + "github.com/go-resty/resty/v2" +) + +// Config contain the value to access on Kibana API +type Config struct { + Address string + Username string + Password string + ApiKey string + DisableVerifySSL bool + CAs []string +} + +// Client contain the REST client and the API specification +type Client struct { + *kbapi.API + Client *resty.Client +} + +// NewDefaultClient init client with empty config +func NewDefaultClient() (*Client, error) { + return NewClient(Config{}) +} + +// NewClient init client with custom config +func NewClient(cfg Config) (*Client, error) { + if cfg.Address == "" { + cfg.Address = "http://localhost:5601" + } + + restyClient := resty.New(). + SetBaseURL(cfg.Address). + SetHeader("kbn-xsrf", "true"). + SetHeader("Content-Type", "application/json") + + if cfg.ApiKey != "" { + restyClient.SetAuthScheme("ApiKey").SetAuthToken(cfg.ApiKey) + } else { + restyClient.SetBasicAuth(cfg.Username, cfg.Password) + } + + for _, path := range cfg.CAs { + restyClient.SetRootCertificate(path) + } + + client := &Client{ + Client: restyClient, + API: kbapi.New(restyClient), + } + + if cfg.DisableVerifySSL { + client.Client.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}) + } + + return client, nil + +} diff --git a/libs/go-kibana-rest/kibana_test.go b/libs/go-kibana-rest/kibana_test.go new file mode 100644 index 000000000..5eed29a0c --- /dev/null +++ b/libs/go-kibana-rest/kibana_test.go @@ -0,0 +1,57 @@ +package kibana + +import ( + "testing" + + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + prefixed "github.com/x-cray/logrus-prefixed-formatter" +) + +type KBTestSuite struct { + suite.Suite +} + +func (s *KBTestSuite) SetupSuite() { + + // Init logger + logrus.SetFormatter(new(prefixed.TextFormatter)) + logrus.SetLevel(logrus.DebugLevel) + +} + +func (s *KBTestSuite) SetupTest() { + + // Do somethink before each test + +} + +func TestKBTestSuite(t *testing.T) { + suite.Run(t, new(KBTestSuite)) +} + +func (s *KBTestSuite) TestNewClient() { + + cfg := Config{ + Address: "http://127.0.0.1:5601", + Username: "elastic", + Password: "changeme", + DisableVerifySSL: true, + } + + client, err := NewClient(cfg) + + assert.NoError(s.T(), err) + assert.NotNil(s.T(), client) + +} + +func (s *KBTestSuite) TestNewDefaultClient() { + + client, err := NewDefaultClient() + + assert.NoError(s.T(), err) + assert.NotNil(s.T(), client) + +} diff --git a/provider/provider_test.go b/provider/provider_test.go index e778a88f4..fdb7a9313 100644 --- a/provider/provider_test.go +++ b/provider/provider_test.go @@ -59,20 +59,69 @@ func TestFleetConfiguration(t *testing.T) { } func TestKibanaConfiguration(t *testing.T) { - envConfig := config.NewFromEnv("acceptance-testing") - - resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ProtoV6ProviderFactories: acctest.Providers, - Steps: []resource.TestStep{ - { - Config: testKibanaConfiguration(envConfig), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("elasticstack_kibana_space.acc_test", "name"), - ), + var envConfig config.Client + + testCases := []struct { + name string + tc func() resource.TestCase + pre func(t *testing.T) + post func(t *testing.T) + }{ + { + name: "with username and password", + pre: func(t *testing.T) { + envConfig = config.NewFromEnv("acceptance-testing") + }, + post: func(t *testing.T) {}, + tc: func() resource.TestCase { + return resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ProtoV6ProviderFactories: acctest.Providers, + Steps: []resource.TestStep{ + { + Config: testKibanaConfiguration(envConfig), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("elasticstack_kibana_space.acc_test", "name"), + ), + }, + }, + } }, }, - }) + { + name: "with api key", + pre: func(t *testing.T) { + apiKey := os.Getenv("KIBANA_API_KEY") + t.Setenv("KIBANA_USERNAME", "") + t.Setenv("KIBANA_PASSWORD", "") + t.Setenv("KIBANA_API_KEY", apiKey) + envConfig = config.NewFromEnv("acceptance-testing") + }, + post: func(t *testing.T) {}, + tc: func() resource.TestCase { + return resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ProtoV6ProviderFactories: acctest.Providers, + Steps: []resource.TestStep{ + { + Config: testKibanaApiKeyConfiguration(envConfig), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("elasticstack_kibana_space.acc_test", "name"), + ), + }, + }, + } + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + tc.pre(t) + resource.Test(t, tc.tc()) + tc.post(t) + }) + + } } func testKibanaConfiguration(cfg config.Client) string { @@ -92,6 +141,22 @@ resource "elasticstack_kibana_space" "acc_test" { }`, cfg.Kibana.Address, cfg.Kibana.Username, cfg.Kibana.Password) } +func testKibanaApiKeyConfiguration(cfg config.Client) string { + return fmt.Sprintf(` +provider "elasticstack" { + elasticsearch {} + kibana { + endpoints = ["%s"] + api_key = "%s" + } +} + +resource "elasticstack_kibana_space" "acc_test" { + space_id = "acc_test_space" + name = "Acceptance Test Space" +}`, cfg.Kibana.Address, cfg.Kibana.ApiKey) +} + func testFleetConfiguration(cfg config.Client) string { return fmt.Sprintf(` provider "elasticstack" { diff --git a/templates/index.md.tmpl b/templates/index.md.tmpl index 6eb749862..54a5ada79 100644 --- a/templates/index.md.tmpl +++ b/templates/index.md.tmpl @@ -59,6 +59,7 @@ Kibana resources will re-use any Elasticsearch credentials specified, these may - `KIBANA_USERNAME` - The username to use for Kibana authentication - `KIBANA_PASSWORD` - The password to use for Kibana authentication - `KIBANA_ENDPOINT` - The Kibana host to connect to +- `KIBANA_API_KEY` - An Elasticsearch API key to use instead of `KIBANA_USERNAME` and `KIBANA_PASSWORD` Fleet resources will re-use any Kibana or Elasticsearch credentials specified, these may be overridden with the following variables: - `FLEET_USERNAME` - The username to use for Kibana authentication diff --git a/templates/resources/kibana_alerting_rule.md.tmpl b/templates/resources/kibana_alerting_rule.md.tmpl index 03d53510c..b259e8130 100644 --- a/templates/resources/kibana_alerting_rule.md.tmpl +++ b/templates/resources/kibana_alerting_rule.md.tmpl @@ -14,6 +14,13 @@ Creates or updates a Kibana alerting rule. See https://www.elastic.co/guide/en/k {{ tffile "examples/resources/elasticstack_kibana_alerting_rule/resource.tf" }} + +**NOTE:** `api_key` authentication is only supported for alerting rule resources from version 8.8.0 of the Elastic stack. Using an `api_key` will result in an error message like: + +``` +Could not create API key - Unsupported scheme "ApiKey" for granting API Key +``` + {{ .SchemaMarkdown | trimspace }} ## Import From d331672419b8083a3bd0efff31bffafd584d1dea Mon Sep 17 00:00:00 2001 From: Nassim Kammah Date: Thu, 23 Nov 2023 14:56:11 +0100 Subject: [PATCH 06/12] Fix buildkite release pipeline (#492) * Fix up the release pipeline * Update release pipeline to only trigger on tags * Use go 1.21 per tools/go.mod * Fix warning about skip argument * Try building only windows amd64 * move amd64 at the end * Bump down parralelism --- .buildkite/hooks/pre-command | 11 ++++++++- .buildkite/release.yml | 2 ++ .buildkite/scripts/release.sh | 41 ++++--------------------------- .ci/pipelines/release.Jenkinsfile | 2 +- .goreleaser.yml | 2 +- Makefile | 8 +++--- catalog-info.yaml | 6 +++++ 7 files changed, 29 insertions(+), 43 deletions(-) diff --git a/.buildkite/hooks/pre-command b/.buildkite/hooks/pre-command index 5fcc8e4b1..32b51d880 100755 --- a/.buildkite/hooks/pre-command +++ b/.buildkite/hooks/pre-command @@ -3,5 +3,14 @@ set -euo pipefail echo "--- Golang version:" -export GO_VERSION="1.20" +export GO_VERSION="1.21" echo "${GO_VERSION}" + +VAULT_PATH=secret/ci/elastic-terraform-provider-elasticstack/terraform-provider-secrets + +if [[ "$BUILDKITE_PIPELINE_SLUG" == "terraform-provider-elasticstack-release" ]]; then + export GPG_PRIVATE_SECRET=$(scripts/retry.sh 5 vault kv get -field gpg_private ${VAULT_PATH}) + export GPG_PASSPHRASE_SECRET=$(scripts/retry.sh 5 vault kv get -field gpg_passphrase ${VAULT_PATH}) + export GPG_FINGERPRINT_SECRET=$(scripts/retry.sh 5 vault kv get -field gpg_fingerprint ${VAULT_PATH}) + export GITHUB_TOKEN=$(scripts/retry.sh 5 vault kv get -field gh_personal_access_token ${VAULT_PATH}) +fi diff --git a/.buildkite/release.yml b/.buildkite/release.yml index 9cff88e78..6b93a1599 100644 --- a/.buildkite/release.yml +++ b/.buildkite/release.yml @@ -2,5 +2,7 @@ steps: - label: Release agents: image: golang:${GO_VERSION} + cpu: "8" + memory: "4G" command: - ".buildkite/scripts/release.sh" diff --git a/.buildkite/scripts/release.sh b/.buildkite/scripts/release.sh index 3d9e22d88..0d5d4f6b2 100755 --- a/.buildkite/scripts/release.sh +++ b/.buildkite/scripts/release.sh @@ -2,45 +2,14 @@ set -euo pipefail -cleanup() { - ARG=${?} - echo "--- Clean up" - - unset GPG_FINGERPRINT_SECRET - # unset GITHUB_TOKEN - rm -rf dist bin - exit ${ARG} -} - -trap cleanup EXIT - echo "--- Download dependencies" make vendor -echo "--- Import gpg key" - -GITHUB_ORGANIZATION=elastic -REPO_NAME=terraform-provider-elasticstack -VAULT_PATH=secret/ci/${GITHUB_ORGANIZATION}-${REPO_NAME} - -GPG_PRIVATE_SECRET=$(vault read -field=gpg_private ${VAULT_PATH} | base64 -d) - -GPG_PASSPHRASE_SECRET=$(vault read -field=gpg_passphrase ${VAULT_PATH}) +echo "--- Importing GPG key" +echo -n "$GPG_PRIVATE_SECRET" | base64 --decode | gpg --import --batch --yes --passphrase "$GPG_PASSPHRASE_SECRET" -cat ${GPG_PASSPHRASE_SECRET} | gpg --import --batch --yes --passphrase-fd 0 ${GPG_PRIVATE_SECRET} - -echo "--- Cache GPG key and release the binaries" - -cat ${GPG_PASSPHRASE_SECRET} | gpg --armor --detach-sign --passphrase-fd 0 --pinentry-mode loopback +echo "--- Caching GPG passphrase" +echo "$GPG_PASSPHRASE_SECRET" | gpg --armor --detach-sign --passphrase-fd 0 --pinentry-mode loopback echo "--- Release the binaries" - -# 'make release' calls 'goreleaser' that needs GPG_FINGERPRINT_SECRET and GITHUB_TOKEN env vars -export GPG_FINGERPRINT_SECRET=$(vault read -field=gpg_fingerprint ${VAULT_PATH} | xargs) - -## TODO -## goreleaser needs GH token to publish binaries to GH -## it's commented out while the BK pipeline is being tested -# export GITHUB_TOKEN=$(vault read -field=github_release_token ${VAULT_PATH} | xargs) - -make release +make release-no-publish diff --git a/.ci/pipelines/release.Jenkinsfile b/.ci/pipelines/release.Jenkinsfile index 8792b4fbc..98e92ff50 100644 --- a/.ci/pipelines/release.Jenkinsfile +++ b/.ci/pipelines/release.Jenkinsfile @@ -28,7 +28,7 @@ node('docker && gobld/machineType:n1-highcpu-8') { stage("Cache GPG key and release the binaries") { script { env.GITHUB_TOKEN = readFile(".ci/.github_token").trim() - env.GPG_FINGERPRINT = readFile(".ci/.gpg_fingerprint").trim() + env.GPG_FINGERPRINT_SECRET = readFile(".ci/.gpg_fingerprint").trim() } sh 'pwd; make -C .ci cache-gpg-passphrase; make release' } diff --git a/.goreleaser.yml b/.goreleaser.yml index ecbb02ef3..9f20a1a89 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -21,10 +21,10 @@ builds: - linux - darwin goarch: - - amd64 - '386' - arm - arm64 + - amd64 ignore: - goos: darwin goarch: '386' diff --git a/Makefile b/Makefile index d7b159b58..aea69c3d1 100644 --- a/Makefile +++ b/Makefile @@ -212,18 +212,18 @@ release-snapshot: tools ## Make local-only test release to see if it works using .PHONY: release-no-publish release-no-publish: tools check-sign-release ## Make a release without publishing artifacts - @ $(GOBIN)/goreleaser release --skip-publish --skip-announce --skip-validate + @ $(GOBIN)/goreleaser release --skip=publish,announce,validate --parallelism=2 .PHONY: release release: tools check-sign-release check-publish-release ## Build, sign, and upload your release - @ $(GOBIN)/goreleaser release --clean + @ $(GOBIN)/goreleaser release --clean --parallelism=4 .PHONY: check-sign-release check-sign-release: -ifndef GPG_FINGERPRINT - $(error GPG_FINGERPRINT is undefined, but required for signing the release) +ifndef GPG_FINGERPRINT_SECRET + $(error GPG_FINGERPRINT_SECRET is undefined, but required for signing the release) endif diff --git a/catalog-info.yaml b/catalog-info.yaml index 898350095..78597a5ff 100644 --- a/catalog-info.yaml +++ b/catalog-info.yaml @@ -22,6 +22,12 @@ spec: spec: repository: elastic/terraform-provider-elasticstack pipeline_file: ".buildkite/release.yml" + provider_settings: + build_branches: false + build_pull_request_forks: false + build_tags: true + filter_condition: 'build.tag =~ /^v[0-9.]+$/' + filter_enabled: true teams: control-plane-stateful-applications: access_level: MANAGE_BUILD_AND_READ From 6233f9a229189bcc7507c49a5b9913e063afeb5d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Nov 2023 06:11:44 +1100 Subject: [PATCH 07/12] Bump golang.org/x/net from 0.1.0 to 0.17.0 in /libs/go-kibana-rest (#491) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.1.0 to 0.17.0. - [Commits](https://github.com/golang/net/compare/v0.1.0...v0.17.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- libs/go-kibana-rest/go.mod | 8 ++++---- libs/go-kibana-rest/go.sum | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/libs/go-kibana-rest/go.mod b/libs/go-kibana-rest/go.mod index e2d53ae90..2749e0777 100644 --- a/libs/go-kibana-rest/go.mod +++ b/libs/go-kibana-rest/go.mod @@ -17,9 +17,9 @@ require ( github.com/onsi/ginkgo v1.16.5 // indirect github.com/onsi/gomega v1.24.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/crypto v0.1.0 // indirect - golang.org/x/net v0.1.0 // indirect - golang.org/x/sys v0.1.0 // indirect - golang.org/x/term v0.1.0 // indirect + golang.org/x/crypto v0.14.0 // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/term v0.13.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/libs/go-kibana-rest/go.sum b/libs/go-kibana-rest/go.sum index 4a88f4a05..a2f96a073 100644 --- a/libs/go-kibana-rest/go.sum +++ b/libs/go-kibana-rest/go.sum @@ -55,8 +55,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -64,8 +64,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -83,15 +83,15 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= From 86cb705bcfc8b53bbf309de7f0776b3bab01e927 Mon Sep 17 00:00:00 2001 From: Taylor Swanson <90622908+taylor-swanson@users.noreply.github.com> Date: Mon, 27 Nov 2023 19:36:51 -0600 Subject: [PATCH 08/12] Make input optional for Fleet integration policies (#493) * Make input optional for Fleet integration policies - Relaxed the requirement for input for Fleet integration policies. - Certain integrations, such as the Elastic Agent integration, do not require any additional configuration, which means an input would not be provided. * Changelog --- CHANGELOG.md | 1 + docs/resources/fleet_integration_policy.md | 2 +- internal/fleet/integration_policy_resource.go | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ab06bcf2..ada879d9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ### Fixed - Rename fleet package objects to `elasticstack_fleet_integration` and `elasticstack_fleet_integration_policy` ([#476](https://github.com/elastic/terraform-provider-elasticstack/pull/476)) - Fix a provider crash when managing SLOs outside of the default Kibana space. ([#485](https://github.com/elastic/terraform-provider-elasticstack/pull/485)) +- Make input optional for `elasticstack_fleet_integration_policy` ([#493](https://github.com/elastic/terraform-provider-elasticstack/pull/493)) ## [0.10.0] - 2023-11-02 diff --git a/docs/resources/fleet_integration_policy.md b/docs/resources/fleet_integration_policy.md index a778bc94a..3b098e529 100644 --- a/docs/resources/fleet_integration_policy.md +++ b/docs/resources/fleet_integration_policy.md @@ -83,7 +83,6 @@ resource "elasticstack_fleet_integration_policy" "sample" { ### Required - `agent_policy_id` (String) ID of the agent policy. -- `input` (Block List, Min: 1) (see [below for nested schema](#nestedblock--input)) - `integration_name` (String) The name of the integration package. - `integration_version` (String) The version of the integration package. - `name` (String) The name of the integration policy. @@ -94,6 +93,7 @@ resource "elasticstack_fleet_integration_policy" "sample" { - `description` (String) The description of the integration policy. - `enabled` (Boolean) Enable the integration policy. - `force` (Boolean) Force operations, such as creation and deletion, to occur. +- `input` (Block List) (see [below for nested schema](#nestedblock--input)) - `policy_id` (String) Unique identifier of the integration policy. - `vars_json` (String, Sensitive) Integration-level variables as JSON. diff --git a/internal/fleet/integration_policy_resource.go b/internal/fleet/integration_policy_resource.go index bc1b77ab7..a7a1528bd 100644 --- a/internal/fleet/integration_policy_resource.go +++ b/internal/fleet/integration_policy_resource.go @@ -64,7 +64,7 @@ func ResourceIntegrationPolicy() *schema.Resource { }, "input": { Type: schema.TypeList, - Required: true, + Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "input_id": { From 6c2f52b8d7d65bb541ea01f3f4cd658c363b7ea6 Mon Sep 17 00:00:00 2001 From: Taylor Swanson <90622908+taylor-swanson@users.noreply.github.com> Date: Wed, 29 Nov 2023 13:56:23 -0600 Subject: [PATCH 09/12] Sort Fleet integration policy inputs to ensure consistency (#494) * Sort Fleet integration policy inputs to ensure consistency - When new inputs are read from the Fleet API, the list is sorted according to the existing plan. Any new inputs added from the API will be moved to the end of the list. This ensures a consistency of inputs and prevents unnecssary changes from appearing. * Changelog * Extract sort function and add unit test --- CHANGELOG.md | 1 + internal/fleet/integration_policy_resource.go | 48 ++++++++++++-- internal/fleet/shared_test.go | 63 +++++++++++++++++++ 3 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 internal/fleet/shared_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index ada879d9d..6aa148152 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Rename fleet package objects to `elasticstack_fleet_integration` and `elasticstack_fleet_integration_policy` ([#476](https://github.com/elastic/terraform-provider-elasticstack/pull/476)) - Fix a provider crash when managing SLOs outside of the default Kibana space. ([#485](https://github.com/elastic/terraform-provider-elasticstack/pull/485)) - Make input optional for `elasticstack_fleet_integration_policy` ([#493](https://github.com/elastic/terraform-provider-elasticstack/pull/493)) +- Sort Fleet integration policy inputs to ensure consistency ([#494](https://github.com/elastic/terraform-provider-elasticstack/pull/494)) ## [0.10.0] - 2023-11-02 diff --git a/internal/fleet/integration_policy_resource.go b/internal/fleet/integration_policy_resource.go index a7a1528bd..e5a63422a 100644 --- a/internal/fleet/integration_policy_resource.go +++ b/internal/fleet/integration_policy_resource.go @@ -3,6 +3,7 @@ package fleet import ( "context" "encoding/json" + "sort" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -340,9 +341,9 @@ func resourceIntegrationPolicyRead(ctx context.Context, d *schema.ResourceData, } } - var inputs []any + newInputs := make([]any, 0, len(pkgPolicy.Inputs)) for inputID, input := range pkgPolicy.Inputs { - inputMap := map[string]any{ + inputData := map[string]any{ "input_id": inputID, "enabled": input.Enabled, } @@ -352,19 +353,23 @@ func resourceIntegrationPolicyRead(ctx context.Context, d *schema.ResourceData, if err != nil { return diag.FromErr(err) } - inputMap["streams_json"] = string(data) + inputData["streams_json"] = string(data) } if input.Vars != nil { data, err := json.Marshal(*input.Vars) if err != nil { return diag.FromErr(err) } - inputMap["vars_json"] = string(data) + inputData["vars_json"] = string(data) } - inputs = append(inputs, inputMap) + newInputs = append(newInputs, inputData) } - if err := d.Set("input", inputs); err != nil { + + existingInputs, _ := d.Get("input").([]any) + sortInputs(newInputs, existingInputs) + + if err := d.Set("input", newInputs); err != nil { return diag.FromErr(err) } @@ -386,3 +391,34 @@ func resourceIntegrationPolicyDelete(ctx context.Context, d *schema.ResourceData return diags } + +// sortInputs will sort the 'incoming' list of input definitions based on +// the order of inputs defined in the 'existing' list. Inputs not present in +// 'existing' will be placed at the end of the list. Inputs are identified by +// their ID ('input_id'). The 'incoming' slice will be sorted in-place. +func sortInputs(incoming []any, existing []any) { + idToIndex := make(map[string]int, len(existing)) + for i, v := range existing { + inputData, _ := v.(map[string]any) + inputID, _ := inputData["input_id"].(string) + idToIndex[inputID] = i + } + + sort.Slice(incoming, func(i, j int) bool { + iInput, _ := incoming[i].(map[string]any) + iID, _ := iInput["input_id"].(string) + iIdx, ok := idToIndex[iID] + if !ok { + return false + } + + jInput, _ := incoming[j].(map[string]any) + jID, _ := jInput["input_id"].(string) + jIdx, ok := idToIndex[jID] + if !ok { + return true + } + + return iIdx < jIdx + }) +} diff --git a/internal/fleet/shared_test.go b/internal/fleet/shared_test.go new file mode 100644 index 000000000..2b767880c --- /dev/null +++ b/internal/fleet/shared_test.go @@ -0,0 +1,63 @@ +package fleet + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_SortInputs(t *testing.T) { + t.Run("WithExisting", func(t *testing.T) { + existing := []any{ + map[string]any{"input_id": "A", "enabled": true}, + map[string]any{"input_id": "B", "enabled": true}, + map[string]any{"input_id": "C", "enabled": true}, + map[string]any{"input_id": "D", "enabled": true}, + map[string]any{"input_id": "E", "enabled": true}, + } + + incoming := []any{ + map[string]any{"input_id": "G", "enabled": true}, + map[string]any{"input_id": "F", "enabled": true}, + map[string]any{"input_id": "B", "enabled": true}, + map[string]any{"input_id": "E", "enabled": true}, + map[string]any{"input_id": "C", "enabled": true}, + } + + want := []any{ + map[string]any{"input_id": "B", "enabled": true}, + map[string]any{"input_id": "C", "enabled": true}, + map[string]any{"input_id": "E", "enabled": true}, + map[string]any{"input_id": "G", "enabled": true}, + map[string]any{"input_id": "F", "enabled": true}, + } + + sortInputs(incoming, existing) + + require.Equal(t, want, incoming) + }) + + t.Run("WithEmpty", func(t *testing.T) { + var existing []any + + incoming := []any{ + map[string]any{"input_id": "G", "enabled": true}, + map[string]any{"input_id": "F", "enabled": true}, + map[string]any{"input_id": "B", "enabled": true}, + map[string]any{"input_id": "E", "enabled": true}, + map[string]any{"input_id": "C", "enabled": true}, + } + + want := []any{ + map[string]any{"input_id": "G", "enabled": true}, + map[string]any{"input_id": "F", "enabled": true}, + map[string]any{"input_id": "B", "enabled": true}, + map[string]any{"input_id": "E", "enabled": true}, + map[string]any{"input_id": "C", "enabled": true}, + } + + sortInputs(incoming, existing) + + require.Equal(t, want, incoming) + }) +} From 88e23d9c642f7e55f7b8387cf53f239c21f48307 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20Haro?= Date: Fri, 1 Dec 2023 08:56:27 +0100 Subject: [PATCH 10/12] [Kibana SLO] Add `tags` support (#495) Co-authored-by: Toby Brain --- CHANGELOG.md | 1 + Makefile | 2 +- README.md | 2 +- docs/resources/kibana_slo.md | 2 + .../elasticstack_kibana_slo/resource.tf | 1 + generated/slo-spec.yml | 254 +++++++++++++++- generated/slo/.openapi-generator/FILES | 18 ++ generated/slo/README.md | 16 +- generated/slo/api/openapi.yaml | 287 +++++++++++++++++- generated/slo/api_slo.go | 175 +++++++++++ generated/slo/configuration.go | 6 + generated/slo/docs/CreateSloRequest.md | 26 ++ .../slo/docs/CreateSloRequestIndicator.md | 10 +- .../slo/docs/DeleteSloInstancesRequest.md | 51 ++++ .../DeleteSloInstancesRequestListInner.md | 72 +++++ .../slo/docs/HistoricalSummaryRequest.md | 22 +- .../IndicatorPropertiesCustomKqlParams.md | 16 +- .../IndicatorPropertiesCustomMetricParams.md | 9 +- .../IndicatorPropertiesTimesliceMetric.md | 72 +++++ ...ndicatorPropertiesTimesliceMetricParams.md | 119 ++++++++ ...orPropertiesTimesliceMetricParamsMetric.md | 114 +++++++ ...TimesliceMetricParamsMetricMetricsInner.md | 140 +++++++++ generated/slo/docs/SloApi.md | 73 +++++ generated/slo/docs/SloResponse.md | 23 +- generated/slo/docs/SloResponseIndicator.md | 10 +- .../TimesliceMetricBasicMetricWithField.md | 119 ++++++++ .../slo/docs/TimesliceMetricDocCountMetric.md | 98 ++++++ .../docs/TimesliceMetricPercentileMetric.md | 140 +++++++++ generated/slo/docs/UpdateSloRequest.md | 26 ++ generated/slo/model_create_slo_request.go | 37 +++ .../slo/model_create_slo_request_indicator.go | 30 ++ .../slo/model_delete_slo_instances_request.go | 116 +++++++ ...delete_slo_instances_request_list_inner.go | 144 +++++++++ .../slo/model_historical_summary_request.go | 26 +- ..._indicator_properties_custom_kql_params.go | 68 ++--- ...dicator_properties_custom_metric_params.go | 35 ++- ...l_indicator_properties_timeslice_metric.go | 143 +++++++++ ...ator_properties_timeslice_metric_params.go | 208 +++++++++++++ ...operties_timeslice_metric_params_metric.go | 200 ++++++++++++ ...lice_metric_params_metric_metrics_inner.go | 121 ++++++++ generated/slo/model_slo_response.go | 30 +- generated/slo/model_slo_response_indicator.go | 40 +++ ...imeslice_metric_basic_metric_with_field.go | 209 +++++++++++++ ...model_timeslice_metric_doc_count_metric.go | 181 +++++++++++ ...odel_timeslice_metric_percentile_metric.go | 237 +++++++++++++++ generated/slo/model_update_slo_request.go | 37 +++ internal/clients/kibana/slo.go | 4 + internal/clients/kibana/slo_test.go | 63 ++++ internal/kibana/slo.go | 24 +- internal/kibana/slo_test.go | 51 +++- internal/models/slo.go | 1 + 51 files changed, 3769 insertions(+), 140 deletions(-) create mode 100644 generated/slo/docs/DeleteSloInstancesRequest.md create mode 100644 generated/slo/docs/DeleteSloInstancesRequestListInner.md create mode 100644 generated/slo/docs/IndicatorPropertiesTimesliceMetric.md create mode 100644 generated/slo/docs/IndicatorPropertiesTimesliceMetricParams.md create mode 100644 generated/slo/docs/IndicatorPropertiesTimesliceMetricParamsMetric.md create mode 100644 generated/slo/docs/IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner.md create mode 100644 generated/slo/docs/TimesliceMetricBasicMetricWithField.md create mode 100644 generated/slo/docs/TimesliceMetricDocCountMetric.md create mode 100644 generated/slo/docs/TimesliceMetricPercentileMetric.md create mode 100644 generated/slo/model_delete_slo_instances_request.go create mode 100644 generated/slo/model_delete_slo_instances_request_list_inner.go create mode 100644 generated/slo/model_indicator_properties_timeslice_metric.go create mode 100644 generated/slo/model_indicator_properties_timeslice_metric_params.go create mode 100644 generated/slo/model_indicator_properties_timeslice_metric_params_metric.go create mode 100644 generated/slo/model_indicator_properties_timeslice_metric_params_metric_metrics_inner.go create mode 100644 generated/slo/model_timeslice_metric_basic_metric_with_field.go create mode 100644 generated/slo/model_timeslice_metric_doc_count_metric.go create mode 100644 generated/slo/model_timeslice_metric_percentile_metric.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 6aa148152..15a9c32a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Added - Switch to Terraform [protocol version 6](https://developer.hashicorp.com/terraform/plugin/terraform-plugin-protocol#protocol-version-6) that is compatible with Terraform CLI version 1.0 and later. - Add 'elasticstack_fleet_package' data source ([#469](https://github.com/elastic/terraform-provider-elasticstack/pull/469)) +- Add `tags` option to Kibana's SLOs ([#495](https://github.com/elastic/terraform-provider-elasticstack/pull/495)) ### Fixed - Rename fleet package objects to `elasticstack_fleet_integration` and `elasticstack_fleet_integration_policy` ([#476](https://github.com/elastic/terraform-provider-elasticstack/pull/476)) diff --git a/Makefile b/Makefile index aea69c3d1..0fad2a50c 100644 --- a/Makefile +++ b/Makefile @@ -69,7 +69,7 @@ retry = until [ $$(if [ -z "$$attempt" ]; then echo -n "0"; else echo -n "$$atte done # To run specific test (e.g. TestAccResourceActionConnector) execute `make docker-testacc TESTARGS='-run ^TestAccResourceActionConnector$$'` -# To enable tracing (or debugging), execute `make docker-testacc TFLOG=TRACE` +# To enable tracing (or debugging), execute `make docker-testacc TF_LOG=TRACE` .PHONY: docker-testacc docker-testacc: docker-elasticsearch docker-kibana ## Run acceptance tests in the docker container @ docker run --rm \ diff --git a/README.md b/README.md index d244b61ac..9adefc90d 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ If you wish to work on the provider, you'll first need [Go](http://www.golang.or To compile the provider, run `go install`. This will build the provider and put the provider binary in the `$GOPATH/bin` directory. -To install the provider locally into the `~/.terraform.d/plugins/...` directory one can use `make install` command. This will allow to refer this provider dirrecty in the Terraform configuration without needing to download it from the registry. +To install the provider locally into the `~/.terraform.d/plugins/...` directory one can use `make install` command. This will allow to refer this provider directly in the Terraform configuration without needing to download it from the registry. To generate or update documentation, run `make gen`. All the generated docs will have to be committed to the repository as well. diff --git a/docs/resources/kibana_slo.md b/docs/resources/kibana_slo.md index 9f0fe181c..41e543dd6 100644 --- a/docs/resources/kibana_slo.md +++ b/docs/resources/kibana_slo.md @@ -148,6 +148,7 @@ resource "elasticstack_kibana_slo" "custom_histogram" { timeslice_window = "5m" } + tags = ["tag-1", "another_tag"] } //Available from 8.10.0 @@ -214,6 +215,7 @@ resource "elasticstack_kibana_slo" "custom_metric" { - `metric_custom_indicator` (Block List, Max: 1) (see [below for nested schema](#nestedblock--metric_custom_indicator)) - `settings` (Block List, Max: 1) The default settings should be sufficient for most users, but if needed, these properties can be overwritten. (see [below for nested schema](#nestedblock--settings)) - `space_id` (String) An identifier for the space. If space_id is not provided, the default space is used. +- `tags` (List of String) The tags for the SLO. ### Nested Schema for `objective` diff --git a/examples/resources/elasticstack_kibana_slo/resource.tf b/examples/resources/elasticstack_kibana_slo/resource.tf index 28200c08e..be8b94aa3 100644 --- a/examples/resources/elasticstack_kibana_slo/resource.tf +++ b/examples/resources/elasticstack_kibana_slo/resource.tf @@ -133,6 +133,7 @@ resource "elasticstack_kibana_slo" "custom_histogram" { timeslice_window = "5m" } + tags = ["tag-1", "another_tag"] } //Available from 8.10.0 diff --git a/generated/slo-spec.yml b/generated/slo-spec.yml index 34d4b4c7b..5aa20726b 100644 --- a/generated/slo-spec.yml +++ b/generated/slo-spec.yml @@ -17,8 +17,6 @@ security: tags: - name: slo description: SLO APIs enable you to define, manage and track service-level objectives - - name: composite slo - description: Composite SLO APIs enable you to define, manage and track a group of SLOs. paths: /s/{spaceId}/api/observability/slos: post: @@ -99,6 +97,7 @@ paths: schema: type: integer default: 25 + maximum: 5000 example: 25 - name: sortBy in: query @@ -408,6 +407,46 @@ paths: application/json: schema: $ref: '#/components/schemas/403_response' + /s/{spaceId}/api/observability/slos/_delete_instances: + post: + summary: Batch delete rollup and summary data for the matching list of sloId and instanceId + operationId: deleteSloInstancesOp + description: | + You must have `all` privileges for the **SLOs** feature in the **Observability** section of the Kibana feature privileges. + tags: + - slo + parameters: + - $ref: '#/components/parameters/kbn_xsrf' + - $ref: '#/components/parameters/space_id' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/delete_slo_instances_request' + responses: + '204': + description: Successful request + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/403_response' + servers: + - url: https://localhost:5601 components: securitySchemes: basicAuth: @@ -416,7 +455,8 @@ components: apiKeyAuth: type: apiKey in: header - name: ApiKey + name: Authorization + description: 'e.g. Authorization: ApiKey base64AccessApiKey' parameters: kbn_xsrf: schema: @@ -504,6 +544,8 @@ components: required: - index - timestampField + - good + - total properties: index: description: The index or index pattern to use @@ -599,7 +641,6 @@ components: - timestampField - good - total - - filter properties: index: description: The index or index pattern to use @@ -797,6 +838,162 @@ components: description: The type of indicator. type: string example: sli.histogram.custom + timeslice_metric_basic_metric_with_field: + title: Timeslice Metric Basic Metric with Field + required: + - name + - aggregation + - field + type: object + properties: + name: + description: The name of the metric. Only valid options are A-Z + type: string + example: A + pattern: ^[A-Z]$ + aggregation: + description: The aggregation type of the metric. + type: string + example: sum + enum: + - sum + - avg + - min + - max + - std_deviation + - last_value + - cardinality + field: + description: The field of the metric. + type: string + example: processor.processed + filter: + description: The filter to apply to the metric. + type: string + example: 'processor.outcome: "success"' + timeslice_metric_percentile_metric: + title: Timeslice Metric Percentile Metric + required: + - name + - aggregation + - field + - percentile + type: object + properties: + name: + description: The name of the metric. Only valid options are A-Z + type: string + example: A + pattern: ^[A-Z]$ + aggregation: + description: The aggregation type of the metric. Only valid option is "percentile" + type: string + example: percentile + enum: + - percentile + field: + description: The field of the metric. + type: string + example: processor.processed + percentile: + description: The percentile value. + type: number + example: 95 + filter: + description: The filter to apply to the metric. + type: string + example: 'processor.outcome: "success"' + timeslice_metric_doc_count_metric: + title: Timeslice Metric Doc Count Metric + required: + - name + - aggregation + type: object + properties: + name: + description: The name of the metric. Only valid options are A-Z + type: string + example: A + pattern: ^[A-Z]$ + aggregation: + description: The aggregation type of the metric. Only valid option is "doc_count" + type: string + example: doc_count + enum: + - doc_count + filter: + description: The filter to apply to the metric. + type: string + example: 'processor.outcome: "success"' + indicator_properties_timeslice_metric: + title: Timeslice metric + required: + - type + - params + description: Defines properties for a timeslice metric indicator type + type: object + properties: + params: + description: An object containing the indicator parameters. + type: object + nullable: false + required: + - index + - timestampField + - metric + properties: + index: + description: The index or index pattern to use + type: string + example: my-service-* + filter: + description: the KQL query to filter the documents with. + type: string + example: 'field.environment : "production" and service.name : "my-service"' + timestampField: + description: | + The timestamp field used in the source indice. + type: string + example: timestamp + metric: + description: | + An object defining the metrics, equation, and threshold to determine if it's a good slice or not + type: object + required: + - metrics + - equation + - comparator + - threshold + properties: + metrics: + description: List of metrics with their name, aggregation type, and field. + type: array + items: + anyOf: + - $ref: '#/components/schemas/timeslice_metric_basic_metric_with_field' + - $ref: '#/components/schemas/timeslice_metric_percentile_metric' + - $ref: '#/components/schemas/timeslice_metric_doc_count_metric' + equation: + description: The equation to calculate the metric. + type: string + example: A + comparator: + description: The comparator to use to compare the equation to the threshold. + type: string + example: GT + enum: + - GT + - GTE + - LT + - LTE + threshold: + description: The threshold used to determine if the metric is a good slice or not. + type: number + example: 100 + type: + description: The type of indicator. + type: string + example: sli.metric.timeslice time_window: title: Time window required: @@ -923,6 +1120,7 @@ components: - enabled - groupBy - instanceId + - tags - createdAt - updatedAt properties: @@ -947,12 +1145,14 @@ components: sli.apm.transactionDuration: '#/components/schemas/indicator_properties_apm_latency' sli.metric.custom: '#/components/schemas/indicator_properties_custom_metric' sli.histogram.custom: '#/components/schemas/indicator_properties_histogram' + sli.metric.timeslice: '#/components/schemas/indicator_properties_timeslice_metric' oneOf: - $ref: '#/components/schemas/indicator_properties_custom_kql' - $ref: '#/components/schemas/indicator_properties_apm_availability' - $ref: '#/components/schemas/indicator_properties_apm_latency' - $ref: '#/components/schemas/indicator_properties_custom_metric' - $ref: '#/components/schemas/indicator_properties_histogram' + - $ref: '#/components/schemas/indicator_properties_timeslice_metric' timeWindow: $ref: '#/components/schemas/time_window' budgetingMethod: @@ -979,6 +1179,11 @@ components: description: the value derived from the groupBy field, if present, otherwise '*' type: string example: host-abcde + tags: + description: List of tags + type: array + items: + type: string createdAt: description: The creation date type: string @@ -1104,6 +1309,7 @@ components: - $ref: '#/components/schemas/indicator_properties_apm_latency' - $ref: '#/components/schemas/indicator_properties_custom_metric' - $ref: '#/components/schemas/indicator_properties_histogram' + - $ref: '#/components/schemas/indicator_properties_timeslice_metric' timeWindow: $ref: '#/components/schemas/time_window' budgetingMethod: @@ -1116,6 +1322,11 @@ components: description: optional group by field to use to generate an SLO per distinct value type: string example: some.field + tags: + description: List of tags + type: array + items: + type: string create_slo_response: title: Create SLO response type: object @@ -1161,6 +1372,7 @@ components: - $ref: '#/components/schemas/indicator_properties_apm_latency' - $ref: '#/components/schemas/indicator_properties_custom_metric' - $ref: '#/components/schemas/indicator_properties_histogram' + - $ref: '#/components/schemas/indicator_properties_timeslice_metric' timeWindow: $ref: '#/components/schemas/time_window' budgetingMethod: @@ -1169,13 +1381,18 @@ components: $ref: '#/components/schemas/objective' settings: $ref: '#/components/schemas/settings' + tags: + description: List of tags + type: array + items: + type: string historical_summary_request: title: Historical summary request type: object required: - - sloIds + - list properties: - sloIds: + list: description: The list of SLO identifiers to get the historical summary for type: array items: @@ -1199,3 +1416,28 @@ components: example: 0.9836 errorBudget: $ref: '#/components/schemas/error_budget' + delete_slo_instances_request: + title: Delete SLO instances request + description: | + The delete SLO instances request takes a list of SLO id and instance id, then delete the rollup and summary data. This API can be used to remove the staled data of an instance SLO that no longer get updated. + type: object + required: + - list + properties: + list: + description: An array of slo id and instance id + type: array + items: + type: object + required: + - sloId + - instanceId + properties: + sloId: + description: The SLO unique identifier + type: string + example: 8853df00-ae2e-11ed-90af-09bb6422b258 + instanceId: + description: The SLO instance identifier + type: string + example: 8853df00-ae2e-11ed-90af-09bb6422b258 diff --git a/generated/slo/.openapi-generator/FILES b/generated/slo/.openapi-generator/FILES index 5d1ca5c6e..6c78451d1 100644 --- a/generated/slo/.openapi-generator/FILES +++ b/generated/slo/.openapi-generator/FILES @@ -10,6 +10,8 @@ docs/BudgetingMethod.md docs/CreateSloRequest.md docs/CreateSloRequestIndicator.md docs/CreateSloResponse.md +docs/DeleteSloInstancesRequest.md +docs/DeleteSloInstancesRequestListInner.md docs/ErrorBudget.md docs/FindSloResponse.md docs/HistoricalSummaryRequest.md @@ -30,6 +32,10 @@ docs/IndicatorPropertiesHistogram.md docs/IndicatorPropertiesHistogramParams.md docs/IndicatorPropertiesHistogramParamsGood.md docs/IndicatorPropertiesHistogramParamsTotal.md +docs/IndicatorPropertiesTimesliceMetric.md +docs/IndicatorPropertiesTimesliceMetricParams.md +docs/IndicatorPropertiesTimesliceMetricParamsMetric.md +docs/IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner.md docs/Model400Response.md docs/Model401Response.md docs/Model403Response.md @@ -43,6 +49,9 @@ docs/SloResponseIndicator.md docs/Summary.md docs/SummaryStatus.md docs/TimeWindow.md +docs/TimesliceMetricBasicMetricWithField.md +docs/TimesliceMetricDocCountMetric.md +docs/TimesliceMetricPercentileMetric.md docs/UpdateSloRequest.md git_push.sh go.mod @@ -56,6 +65,8 @@ model_budgeting_method.go model_create_slo_request.go model_create_slo_request_indicator.go model_create_slo_response.go +model_delete_slo_instances_request.go +model_delete_slo_instances_request_list_inner.go model_error_budget.go model_find_slo_response.go model_historical_summary_request.go @@ -76,6 +87,10 @@ model_indicator_properties_histogram.go model_indicator_properties_histogram_params.go model_indicator_properties_histogram_params_good.go model_indicator_properties_histogram_params_total.go +model_indicator_properties_timeslice_metric.go +model_indicator_properties_timeslice_metric_params.go +model_indicator_properties_timeslice_metric_params_metric.go +model_indicator_properties_timeslice_metric_params_metric_metrics_inner.go model_objective.go model_settings.go model_slo_response.go @@ -83,6 +98,9 @@ model_slo_response_indicator.go model_summary.go model_summary_status.go model_time_window.go +model_timeslice_metric_basic_metric_with_field.go +model_timeslice_metric_doc_count_metric.go +model_timeslice_metric_percentile_metric.go model_update_slo_request.go response.go test/api_slo_test.go diff --git a/generated/slo/README.md b/generated/slo/README.md index 45d046cce..cea692cc2 100644 --- a/generated/slo/README.md +++ b/generated/slo/README.md @@ -78,6 +78,7 @@ All URIs are relative to *http://localhost:5601* Class | Method | HTTP request | Description ------------ | ------------- | ------------- | ------------- *SloAPI* | [**CreateSloOp**](docs/SloAPI.md#createsloop) | **Post** /s/{spaceId}/api/observability/slos | Creates an SLO. +*SloAPI* | [**DeleteSloInstancesOp**](docs/SloAPI.md#deletesloinstancesop) | **Post** /s/{spaceId}/api/observability/slos/_delete_instances | Batch delete rollup and summary data for the matching list of sloId and instanceId *SloAPI* | [**DeleteSloOp**](docs/SloAPI.md#deletesloop) | **Delete** /s/{spaceId}/api/observability/slos/{sloId} | Deletes an SLO *SloAPI* | [**DisableSloOp**](docs/SloAPI.md#disablesloop) | **Post** /s/{spaceId}/api/observability/slos/{sloId}/disable | Disables an SLO *SloAPI* | [**EnableSloOp**](docs/SloAPI.md#enablesloop) | **Post** /s/{spaceId}/api/observability/slos/{sloId}/enable | Enables an SLO @@ -93,6 +94,8 @@ Class | Method | HTTP request | Description - [CreateSloRequest](docs/CreateSloRequest.md) - [CreateSloRequestIndicator](docs/CreateSloRequestIndicator.md) - [CreateSloResponse](docs/CreateSloResponse.md) + - [DeleteSloInstancesRequest](docs/DeleteSloInstancesRequest.md) + - [DeleteSloInstancesRequestListInner](docs/DeleteSloInstancesRequestListInner.md) - [ErrorBudget](docs/ErrorBudget.md) - [FindSloResponse](docs/FindSloResponse.md) - [HistoricalSummaryRequest](docs/HistoricalSummaryRequest.md) @@ -113,6 +116,10 @@ Class | Method | HTTP request | Description - [IndicatorPropertiesHistogramParams](docs/IndicatorPropertiesHistogramParams.md) - [IndicatorPropertiesHistogramParamsGood](docs/IndicatorPropertiesHistogramParamsGood.md) - [IndicatorPropertiesHistogramParamsTotal](docs/IndicatorPropertiesHistogramParamsTotal.md) + - [IndicatorPropertiesTimesliceMetric](docs/IndicatorPropertiesTimesliceMetric.md) + - [IndicatorPropertiesTimesliceMetricParams](docs/IndicatorPropertiesTimesliceMetricParams.md) + - [IndicatorPropertiesTimesliceMetricParamsMetric](docs/IndicatorPropertiesTimesliceMetricParamsMetric.md) + - [IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner](docs/IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner.md) - [Model400Response](docs/Model400Response.md) - [Model401Response](docs/Model401Response.md) - [Model403Response](docs/Model403Response.md) @@ -125,6 +132,9 @@ Class | Method | HTTP request | Description - [Summary](docs/Summary.md) - [SummaryStatus](docs/SummaryStatus.md) - [TimeWindow](docs/TimeWindow.md) + - [TimesliceMetricBasicMetricWithField](docs/TimesliceMetricBasicMetricWithField.md) + - [TimesliceMetricDocCountMetric](docs/TimesliceMetricDocCountMetric.md) + - [TimesliceMetricPercentileMetric](docs/TimesliceMetricPercentileMetric.md) - [UpdateSloRequest](docs/UpdateSloRequest.md) @@ -149,10 +159,10 @@ r, err := client.Service.Operation(auth, args) ### apiKeyAuth - **Type**: API key -- **API key parameter name**: ApiKey +- **API key parameter name**: Authorization - **Location**: HTTP header -Note, each API key must be added to a map of `map[string]APIKey` where the key is: ApiKey and passed in as the auth context for each request. +Note, each API key must be added to a map of `map[string]APIKey` where the key is: Authorization and passed in as the auth context for each request. Example @@ -161,7 +171,7 @@ auth := context.WithValue( context.Background(), sw.ContextAPIKeys, map[string]sw.APIKey{ - "ApiKey": {Key: "API_KEY_STRING"}, + "Authorization": {Key: "API_KEY_STRING"}, }, ) r, err := client.Service.Operation(auth, args) diff --git a/generated/slo/api/openapi.yaml b/generated/slo/api/openapi.yaml index a3cd384b2..d2796a419 100644 --- a/generated/slo/api/openapi.yaml +++ b/generated/slo/api/openapi.yaml @@ -17,9 +17,6 @@ security: tags: - description: "SLO APIs enable you to define, manage and track service-level objectives" name: slo -- description: "Composite SLO APIs enable you to define, manage and track a group\ - \ of SLOs." - name: composite slo paths: /s/{spaceId}/api/observability/slos: get: @@ -72,6 +69,7 @@ paths: required: false schema: default: 25 + maximum: 5000 type: integer style: form - description: Sort by field @@ -595,6 +593,63 @@ paths: summary: Retrieves the historical summary for a list of SLOs tags: - slo + /s/{spaceId}/api/observability/slos/_delete_instances: + post: + description: | + You must have `all` privileges for the **SLOs** feature in the **Observability** section of the Kibana feature privileges. + operationId: deleteSloInstancesOp + parameters: + - description: Cross-site request forgery protection + explode: false + in: header + name: kbn-xsrf + required: true + schema: + type: string + style: simple + - description: "An identifier for the space. If `/s/` and the identifier are\ + \ omitted from the path, the default space is used." + explode: false + in: path + name: spaceId + required: true + schema: + example: default + type: string + style: simple + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/delete_slo_instances_request' + required: true + responses: + "204": + description: Successful request + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/400_response' + description: Bad request + "401": + content: + application/json: + schema: + $ref: '#/components/schemas/401_response' + description: Unauthorized response + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/403_response' + description: Unauthorized response + servers: + - url: https://localhost:5601 + summary: Batch delete rollup and summary data for the matching list of sloId + and instanceId + tags: + - slo components: parameters: kbn_xsrf: @@ -698,6 +753,107 @@ components: - type title: Histogram indicator type: object + timeslice_metric_basic_metric_with_field: + properties: + name: + description: The name of the metric. Only valid options are A-Z + example: A + pattern: "^[A-Z]$" + type: string + aggregation: + description: The aggregation type of the metric. + enum: + - sum + - avg + - min + - max + - std_deviation + - last_value + - cardinality + example: sum + type: string + field: + description: The field of the metric. + example: processor.processed + type: string + filter: + description: The filter to apply to the metric. + example: "processor.outcome: \"success\"" + type: string + required: + - aggregation + - field + - name + title: Timeslice Metric Basic Metric with Field + type: object + timeslice_metric_percentile_metric: + properties: + name: + description: The name of the metric. Only valid options are A-Z + example: A + pattern: "^[A-Z]$" + type: string + aggregation: + description: The aggregation type of the metric. Only valid option is "percentile" + enum: + - percentile + example: percentile + type: string + field: + description: The field of the metric. + example: processor.processed + type: string + percentile: + description: The percentile value. + example: 95 + type: number + filter: + description: The filter to apply to the metric. + example: "processor.outcome: \"success\"" + type: string + required: + - aggregation + - field + - name + - percentile + title: Timeslice Metric Percentile Metric + type: object + timeslice_metric_doc_count_metric: + properties: + name: + description: The name of the metric. Only valid options are A-Z + example: A + pattern: "^[A-Z]$" + type: string + aggregation: + description: The aggregation type of the metric. Only valid option is "doc_count" + enum: + - doc_count + example: doc_count + type: string + filter: + description: The filter to apply to the metric. + example: "processor.outcome: \"success\"" + type: string + required: + - aggregation + - name + title: Timeslice Metric Doc Count Metric + type: object + indicator_properties_timeslice_metric: + description: Defines properties for a timeslice metric indicator type + properties: + params: + $ref: '#/components/schemas/indicator_properties_timeslice_metric_params' + type: + description: The type of indicator. + example: sli.metric.timeslice + type: string + required: + - params + - type + title: Timeslice metric + type: object time_window: description: Defines properties for the SLO time window example: @@ -863,6 +1019,9 @@ components: timesliceTarget: 0.995 target: 0.99 revision: 2 + tags: + - tags + - tags createdAt: 2023-01-12T10:03:19.000Z instanceId: host-abcde name: My Service SLO @@ -912,6 +1071,11 @@ components: \ '*'" example: host-abcde type: string + tags: + description: List of tags + items: + type: string + type: array createdAt: description: The creation date example: 2023-01-12T10:03:19.000Z @@ -934,6 +1098,7 @@ components: - revision - settings - summary + - tags - timeWindow - updatedAt title: SLO response @@ -969,6 +1134,9 @@ components: timesliceTarget: 0.995 target: 0.99 revision: 2 + tags: + - tags + - tags createdAt: 2023-01-12T10:03:19.000Z instanceId: host-abcde name: My Service SLO @@ -998,6 +1166,9 @@ components: timesliceTarget: 0.995 target: 0.99 revision: 2 + tags: + - tags + - tags createdAt: 2023-01-12T10:03:19.000Z instanceId: host-abcde name: My Service SLO @@ -1122,6 +1293,11 @@ components: value example: some.field type: string + tags: + description: List of tags + items: + type: string + type: array required: - budgetingMethod - description @@ -1179,18 +1355,23 @@ components: $ref: '#/components/schemas/objective' settings: $ref: '#/components/schemas/settings' + tags: + description: List of tags + items: + type: string + type: array title: Update SLO request type: object historical_summary_request: properties: - sloIds: + list: description: The list of SLO identifiers to get the historical summary for items: example: 8853df00-ae2e-11ed-90af-09bb6422b258 type: string type: array required: - - sloIds + - list title: Historical summary request type: object historical_summary_response: @@ -1200,6 +1381,19 @@ components: type: array title: Historical summary response type: object + delete_slo_instances_request: + description: | + The delete SLO instances request takes a list of SLO id and instance id, then delete the rollup and summary data. This API can be used to remove the staled data of an instance SLO that no longer get updated. + properties: + list: + description: An array of slo id and instance id + items: + $ref: '#/components/schemas/delete_slo_instances_request_list_inner' + type: array + required: + - list + title: Delete SLO instances request + type: object indicator_properties_apm_availability_params: description: An object containing the indicator parameters. nullable: false @@ -1261,8 +1455,10 @@ components: example: timestamp type: string required: + - good - index - timestampField + - total type: object indicator_properties_apm_latency_params: description: An object containing the indicator parameters. @@ -1412,7 +1608,6 @@ components: total: $ref: '#/components/schemas/indicator_properties_custom_metric_params_total' required: - - filter - good - index - timestampField @@ -1509,6 +1704,68 @@ components: - timestampField - total type: object + indicator_properties_timeslice_metric_params_metric_metrics_inner: + anyOf: + - $ref: '#/components/schemas/timeslice_metric_basic_metric_with_field' + - $ref: '#/components/schemas/timeslice_metric_percentile_metric' + - $ref: '#/components/schemas/timeslice_metric_doc_count_metric' + indicator_properties_timeslice_metric_params_metric: + description: | + An object defining the metrics, equation, and threshold to determine if it's a good slice or not + properties: + metrics: + description: "List of metrics with their name, aggregation type, and field." + items: + $ref: '#/components/schemas/indicator_properties_timeslice_metric_params_metric_metrics_inner' + type: array + equation: + description: The equation to calculate the metric. + example: A + type: string + comparator: + description: The comparator to use to compare the equation to the threshold. + enum: + - GT + - GTE + - LT + - LTE + example: GT + type: string + threshold: + description: The threshold used to determine if the metric is a good slice + or not. + example: 100 + type: number + required: + - comparator + - equation + - metrics + - threshold + type: object + indicator_properties_timeslice_metric_params: + description: An object containing the indicator parameters. + nullable: false + properties: + index: + description: The index or index pattern to use + example: my-service-* + type: string + filter: + description: the KQL query to filter the documents with. + example: "field.environment : \"production\" and service.name : \"my-service\"" + type: string + timestampField: + description: | + The timestamp field used in the source indice. + example: timestamp + type: string + metric: + $ref: '#/components/schemas/indicator_properties_timeslice_metric_params_metric' + required: + - index + - metric + - timestampField + type: object slo_response_indicator: discriminator: mapping: @@ -1517,6 +1774,7 @@ components: sli.apm.transactionDuration: '#/components/schemas/indicator_properties_apm_latency' sli.metric.custom: '#/components/schemas/indicator_properties_custom_metric' sli.histogram.custom: '#/components/schemas/indicator_properties_histogram' + sli.metric.timeslice: '#/components/schemas/indicator_properties_timeslice_metric' propertyName: type oneOf: - $ref: '#/components/schemas/indicator_properties_custom_kql' @@ -1524,6 +1782,7 @@ components: - $ref: '#/components/schemas/indicator_properties_apm_latency' - $ref: '#/components/schemas/indicator_properties_custom_metric' - $ref: '#/components/schemas/indicator_properties_histogram' + - $ref: '#/components/schemas/indicator_properties_timeslice_metric' create_slo_request_indicator: oneOf: - $ref: '#/components/schemas/indicator_properties_custom_kql' @@ -1531,6 +1790,7 @@ components: - $ref: '#/components/schemas/indicator_properties_apm_latency' - $ref: '#/components/schemas/indicator_properties_custom_metric' - $ref: '#/components/schemas/indicator_properties_histogram' + - $ref: '#/components/schemas/indicator_properties_timeslice_metric' Historical_summary_response_inner: properties: date: @@ -1544,11 +1804,26 @@ components: errorBudget: $ref: '#/components/schemas/error_budget' type: object + delete_slo_instances_request_list_inner: + properties: + sloId: + description: The SLO unique identifier + example: 8853df00-ae2e-11ed-90af-09bb6422b258 + type: string + instanceId: + description: The SLO instance identifier + example: 8853df00-ae2e-11ed-90af-09bb6422b258 + type: string + required: + - instanceId + - sloId + type: object securitySchemes: basicAuth: scheme: basic type: http apiKeyAuth: + description: "e.g. Authorization: ApiKey base64AccessApiKey" in: header name: Authorization type: apiKey diff --git a/generated/slo/api_slo.go b/generated/slo/api_slo.go index 31d8c4ada..bd95b7880 100644 --- a/generated/slo/api_slo.go +++ b/generated/slo/api_slo.go @@ -37,6 +37,21 @@ type SloAPI interface { // @return CreateSloResponse CreateSloOpExecute(r ApiCreateSloOpRequest) (*CreateSloResponse, *http.Response, error) + /* + DeleteSloInstancesOp Batch delete rollup and summary data for the matching list of sloId and instanceId + + You must have `all` privileges for the **SLOs** feature in the **Observability** section of the Kibana feature privileges. + + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param spaceId An identifier for the space. If `/s/` and the identifier are omitted from the path, the default space is used. + @return ApiDeleteSloInstancesOpRequest + */ + DeleteSloInstancesOp(ctx context.Context, spaceId string) ApiDeleteSloInstancesOpRequest + + // DeleteSloInstancesOpExecute executes the request + DeleteSloInstancesOpExecute(r ApiDeleteSloInstancesOpRequest) (*http.Response, error) + /* DeleteSloOp Deletes an SLO @@ -338,6 +353,166 @@ func (a *SloAPIService) CreateSloOpExecute(r ApiCreateSloOpRequest) (*CreateSloR return localVarReturnValue, localVarHTTPResponse, nil } +type ApiDeleteSloInstancesOpRequest struct { + ctx context.Context + ApiService SloAPI + kbnXsrf *string + spaceId string + deleteSloInstancesRequest *DeleteSloInstancesRequest +} + +// Cross-site request forgery protection +func (r ApiDeleteSloInstancesOpRequest) KbnXsrf(kbnXsrf string) ApiDeleteSloInstancesOpRequest { + r.kbnXsrf = &kbnXsrf + return r +} + +func (r ApiDeleteSloInstancesOpRequest) DeleteSloInstancesRequest(deleteSloInstancesRequest DeleteSloInstancesRequest) ApiDeleteSloInstancesOpRequest { + r.deleteSloInstancesRequest = &deleteSloInstancesRequest + return r +} + +func (r ApiDeleteSloInstancesOpRequest) Execute() (*http.Response, error) { + return r.ApiService.DeleteSloInstancesOpExecute(r) +} + +/* +DeleteSloInstancesOp Batch delete rollup and summary data for the matching list of sloId and instanceId + +You must have `all` privileges for the **SLOs** feature in the **Observability** section of the Kibana feature privileges. + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param spaceId An identifier for the space. If `/s/` and the identifier are omitted from the path, the default space is used. + @return ApiDeleteSloInstancesOpRequest +*/ +func (a *SloAPIService) DeleteSloInstancesOp(ctx context.Context, spaceId string) ApiDeleteSloInstancesOpRequest { + return ApiDeleteSloInstancesOpRequest{ + ApiService: a, + ctx: ctx, + spaceId: spaceId, + } +} + +// Execute executes the request +func (a *SloAPIService) DeleteSloInstancesOpExecute(r ApiDeleteSloInstancesOpRequest) (*http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "SloAPIService.DeleteSloInstancesOp") + if err != nil { + return nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/s/{spaceId}/api/observability/slos/_delete_instances" + localVarPath = strings.Replace(localVarPath, "{"+"spaceId"+"}", url.PathEscape(parameterValueToString(r.spaceId, "spaceId")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if r.kbnXsrf == nil { + return nil, reportError("kbnXsrf is required and must be specified") + } + if r.deleteSloInstancesRequest == nil { + return nil, reportError("deleteSloInstancesRequest is required and must be specified") + } + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + parameterAddToHeaderOrQuery(localVarHeaderParams, "kbn-xsrf", r.kbnXsrf, "") + // body params + localVarPostBody = r.deleteSloInstancesRequest + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["apiKeyAuth"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + if localVarHTTPResponse.StatusCode == 400 { + var v Model400Response + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 401 { + var v Model401Response + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 403 { + var v Model403Response + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + } + return localVarHTTPResponse, newErr + } + + return localVarHTTPResponse, nil +} + type ApiDeleteSloOpRequest struct { ctx context.Context ApiService SloAPI diff --git a/generated/slo/configuration.go b/generated/slo/configuration.go index 2bbd0944a..2df8d268c 100644 --- a/generated/slo/configuration.go +++ b/generated/slo/configuration.go @@ -107,6 +107,12 @@ func NewConfiguration() *Configuration { Description: "No description provided", }, }, + "SloAPIService.DeleteSloInstancesOp": { + { + URL: "https://localhost:5601", + Description: "No description provided", + }, + }, }, } return cfg diff --git a/generated/slo/docs/CreateSloRequest.md b/generated/slo/docs/CreateSloRequest.md index d3d11f2ec..c56190f41 100644 --- a/generated/slo/docs/CreateSloRequest.md +++ b/generated/slo/docs/CreateSloRequest.md @@ -13,6 +13,7 @@ Name | Type | Description | Notes **Objective** | [**Objective**](Objective.md) | | **Settings** | Pointer to [**Settings**](Settings.md) | | [optional] **GroupBy** | Pointer to **string** | optional group by field to use to generate an SLO per distinct value | [optional] +**Tags** | Pointer to **[]string** | List of tags | [optional] ## Methods @@ -228,6 +229,31 @@ SetGroupBy sets GroupBy field to given value. HasGroupBy returns a boolean if a field has been set. +### GetTags + +`func (o *CreateSloRequest) GetTags() []string` + +GetTags returns the Tags field if non-nil, zero value otherwise. + +### GetTagsOk + +`func (o *CreateSloRequest) GetTagsOk() (*[]string, bool)` + +GetTagsOk returns a tuple with the Tags field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTags + +`func (o *CreateSloRequest) SetTags(v []string)` + +SetTags sets Tags field to given value. + +### HasTags + +`func (o *CreateSloRequest) HasTags() bool` + +HasTags returns a boolean if a field has been set. + [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/generated/slo/docs/CreateSloRequestIndicator.md b/generated/slo/docs/CreateSloRequestIndicator.md index 1075d6d1e..3be9942bb 100644 --- a/generated/slo/docs/CreateSloRequestIndicator.md +++ b/generated/slo/docs/CreateSloRequestIndicator.md @@ -4,14 +4,14 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**Params** | [**IndicatorPropertiesHistogramParams**](IndicatorPropertiesHistogramParams.md) | | +**Params** | [**IndicatorPropertiesTimesliceMetricParams**](IndicatorPropertiesTimesliceMetricParams.md) | | **Type** | **string** | The type of indicator. | ## Methods ### NewCreateSloRequestIndicator -`func NewCreateSloRequestIndicator(params IndicatorPropertiesHistogramParams, type_ string, ) *CreateSloRequestIndicator` +`func NewCreateSloRequestIndicator(params IndicatorPropertiesTimesliceMetricParams, type_ string, ) *CreateSloRequestIndicator` NewCreateSloRequestIndicator instantiates a new CreateSloRequestIndicator object This constructor will assign default values to properties that have it defined, @@ -28,20 +28,20 @@ but it doesn't guarantee that properties required by API are set ### GetParams -`func (o *CreateSloRequestIndicator) GetParams() IndicatorPropertiesHistogramParams` +`func (o *CreateSloRequestIndicator) GetParams() IndicatorPropertiesTimesliceMetricParams` GetParams returns the Params field if non-nil, zero value otherwise. ### GetParamsOk -`func (o *CreateSloRequestIndicator) GetParamsOk() (*IndicatorPropertiesHistogramParams, bool)` +`func (o *CreateSloRequestIndicator) GetParamsOk() (*IndicatorPropertiesTimesliceMetricParams, bool)` GetParamsOk returns a tuple with the Params field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetParams -`func (o *CreateSloRequestIndicator) SetParams(v IndicatorPropertiesHistogramParams)` +`func (o *CreateSloRequestIndicator) SetParams(v IndicatorPropertiesTimesliceMetricParams)` SetParams sets Params field to given value. diff --git a/generated/slo/docs/DeleteSloInstancesRequest.md b/generated/slo/docs/DeleteSloInstancesRequest.md new file mode 100644 index 000000000..2b6b3636c --- /dev/null +++ b/generated/slo/docs/DeleteSloInstancesRequest.md @@ -0,0 +1,51 @@ +# DeleteSloInstancesRequest + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**List** | [**[]DeleteSloInstancesRequestListInner**](DeleteSloInstancesRequestListInner.md) | An array of slo id and instance id | + +## Methods + +### NewDeleteSloInstancesRequest + +`func NewDeleteSloInstancesRequest(list []DeleteSloInstancesRequestListInner, ) *DeleteSloInstancesRequest` + +NewDeleteSloInstancesRequest instantiates a new DeleteSloInstancesRequest object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewDeleteSloInstancesRequestWithDefaults + +`func NewDeleteSloInstancesRequestWithDefaults() *DeleteSloInstancesRequest` + +NewDeleteSloInstancesRequestWithDefaults instantiates a new DeleteSloInstancesRequest object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetList + +`func (o *DeleteSloInstancesRequest) GetList() []DeleteSloInstancesRequestListInner` + +GetList returns the List field if non-nil, zero value otherwise. + +### GetListOk + +`func (o *DeleteSloInstancesRequest) GetListOk() (*[]DeleteSloInstancesRequestListInner, bool)` + +GetListOk returns a tuple with the List field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetList + +`func (o *DeleteSloInstancesRequest) SetList(v []DeleteSloInstancesRequestListInner)` + +SetList sets List field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/generated/slo/docs/DeleteSloInstancesRequestListInner.md b/generated/slo/docs/DeleteSloInstancesRequestListInner.md new file mode 100644 index 000000000..c639bc6ab --- /dev/null +++ b/generated/slo/docs/DeleteSloInstancesRequestListInner.md @@ -0,0 +1,72 @@ +# DeleteSloInstancesRequestListInner + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**SloId** | **string** | The SLO unique identifier | +**InstanceId** | **string** | The SLO instance identifier | + +## Methods + +### NewDeleteSloInstancesRequestListInner + +`func NewDeleteSloInstancesRequestListInner(sloId string, instanceId string, ) *DeleteSloInstancesRequestListInner` + +NewDeleteSloInstancesRequestListInner instantiates a new DeleteSloInstancesRequestListInner object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewDeleteSloInstancesRequestListInnerWithDefaults + +`func NewDeleteSloInstancesRequestListInnerWithDefaults() *DeleteSloInstancesRequestListInner` + +NewDeleteSloInstancesRequestListInnerWithDefaults instantiates a new DeleteSloInstancesRequestListInner object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetSloId + +`func (o *DeleteSloInstancesRequestListInner) GetSloId() string` + +GetSloId returns the SloId field if non-nil, zero value otherwise. + +### GetSloIdOk + +`func (o *DeleteSloInstancesRequestListInner) GetSloIdOk() (*string, bool)` + +GetSloIdOk returns a tuple with the SloId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetSloId + +`func (o *DeleteSloInstancesRequestListInner) SetSloId(v string)` + +SetSloId sets SloId field to given value. + + +### GetInstanceId + +`func (o *DeleteSloInstancesRequestListInner) GetInstanceId() string` + +GetInstanceId returns the InstanceId field if non-nil, zero value otherwise. + +### GetInstanceIdOk + +`func (o *DeleteSloInstancesRequestListInner) GetInstanceIdOk() (*string, bool)` + +GetInstanceIdOk returns a tuple with the InstanceId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetInstanceId + +`func (o *DeleteSloInstancesRequestListInner) SetInstanceId(v string)` + +SetInstanceId sets InstanceId field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/generated/slo/docs/HistoricalSummaryRequest.md b/generated/slo/docs/HistoricalSummaryRequest.md index 5419095c5..c63ad83ec 100644 --- a/generated/slo/docs/HistoricalSummaryRequest.md +++ b/generated/slo/docs/HistoricalSummaryRequest.md @@ -4,13 +4,13 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**SloIds** | **[]string** | The list of SLO identifiers to get the historical summary for | +**List** | **[]string** | The list of SLO identifiers to get the historical summary for | ## Methods ### NewHistoricalSummaryRequest -`func NewHistoricalSummaryRequest(sloIds []string, ) *HistoricalSummaryRequest` +`func NewHistoricalSummaryRequest(list []string, ) *HistoricalSummaryRequest` NewHistoricalSummaryRequest instantiates a new HistoricalSummaryRequest object This constructor will assign default values to properties that have it defined, @@ -25,24 +25,24 @@ NewHistoricalSummaryRequestWithDefaults instantiates a new HistoricalSummaryRequ This constructor will only assign default values to properties that have it defined, but it doesn't guarantee that properties required by API are set -### GetSloIds +### GetList -`func (o *HistoricalSummaryRequest) GetSloIds() []string` +`func (o *HistoricalSummaryRequest) GetList() []string` -GetSloIds returns the SloIds field if non-nil, zero value otherwise. +GetList returns the List field if non-nil, zero value otherwise. -### GetSloIdsOk +### GetListOk -`func (o *HistoricalSummaryRequest) GetSloIdsOk() (*[]string, bool)` +`func (o *HistoricalSummaryRequest) GetListOk() (*[]string, bool)` -GetSloIdsOk returns a tuple with the SloIds field if it's non-nil, zero value otherwise +GetListOk returns a tuple with the List field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. -### SetSloIds +### SetList -`func (o *HistoricalSummaryRequest) SetSloIds(v []string)` +`func (o *HistoricalSummaryRequest) SetList(v []string)` -SetSloIds sets SloIds field to given value. +SetList sets List field to given value. diff --git a/generated/slo/docs/IndicatorPropertiesCustomKqlParams.md b/generated/slo/docs/IndicatorPropertiesCustomKqlParams.md index 8ddbe1dd1..317db1569 100644 --- a/generated/slo/docs/IndicatorPropertiesCustomKqlParams.md +++ b/generated/slo/docs/IndicatorPropertiesCustomKqlParams.md @@ -6,15 +6,15 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **Index** | **string** | The index or index pattern to use | **Filter** | Pointer to **string** | the KQL query to filter the documents with. | [optional] -**Good** | Pointer to **string** | the KQL query used to define the good events. | [optional] -**Total** | Pointer to **string** | the KQL query used to define all events. | [optional] +**Good** | **string** | the KQL query used to define the good events. | +**Total** | **string** | the KQL query used to define all events. | **TimestampField** | **string** | The timestamp field used in the source indice. | ## Methods ### NewIndicatorPropertiesCustomKqlParams -`func NewIndicatorPropertiesCustomKqlParams(index string, timestampField string, ) *IndicatorPropertiesCustomKqlParams` +`func NewIndicatorPropertiesCustomKqlParams(index string, good string, total string, timestampField string, ) *IndicatorPropertiesCustomKqlParams` NewIndicatorPropertiesCustomKqlParams instantiates a new IndicatorPropertiesCustomKqlParams object This constructor will assign default values to properties that have it defined, @@ -93,11 +93,6 @@ and a boolean to check if the value has been set. SetGood sets Good field to given value. -### HasGood - -`func (o *IndicatorPropertiesCustomKqlParams) HasGood() bool` - -HasGood returns a boolean if a field has been set. ### GetTotal @@ -118,11 +113,6 @@ and a boolean to check if the value has been set. SetTotal sets Total field to given value. -### HasTotal - -`func (o *IndicatorPropertiesCustomKqlParams) HasTotal() bool` - -HasTotal returns a boolean if a field has been set. ### GetTimestampField diff --git a/generated/slo/docs/IndicatorPropertiesCustomMetricParams.md b/generated/slo/docs/IndicatorPropertiesCustomMetricParams.md index 4533a8eec..ea6814410 100644 --- a/generated/slo/docs/IndicatorPropertiesCustomMetricParams.md +++ b/generated/slo/docs/IndicatorPropertiesCustomMetricParams.md @@ -5,7 +5,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **Index** | **string** | The index or index pattern to use | -**Filter** | **string** | the KQL query to filter the documents with. | +**Filter** | Pointer to **string** | the KQL query to filter the documents with. | [optional] **TimestampField** | **string** | The timestamp field used in the source indice. | **Good** | [**IndicatorPropertiesCustomMetricParamsGood**](IndicatorPropertiesCustomMetricParamsGood.md) | | **Total** | [**IndicatorPropertiesCustomMetricParamsTotal**](IndicatorPropertiesCustomMetricParamsTotal.md) | | @@ -14,7 +14,7 @@ Name | Type | Description | Notes ### NewIndicatorPropertiesCustomMetricParams -`func NewIndicatorPropertiesCustomMetricParams(index string, filter string, timestampField string, good IndicatorPropertiesCustomMetricParamsGood, total IndicatorPropertiesCustomMetricParamsTotal, ) *IndicatorPropertiesCustomMetricParams` +`func NewIndicatorPropertiesCustomMetricParams(index string, timestampField string, good IndicatorPropertiesCustomMetricParamsGood, total IndicatorPropertiesCustomMetricParamsTotal, ) *IndicatorPropertiesCustomMetricParams` NewIndicatorPropertiesCustomMetricParams instantiates a new IndicatorPropertiesCustomMetricParams object This constructor will assign default values to properties that have it defined, @@ -68,6 +68,11 @@ and a boolean to check if the value has been set. SetFilter sets Filter field to given value. +### HasFilter + +`func (o *IndicatorPropertiesCustomMetricParams) HasFilter() bool` + +HasFilter returns a boolean if a field has been set. ### GetTimestampField diff --git a/generated/slo/docs/IndicatorPropertiesTimesliceMetric.md b/generated/slo/docs/IndicatorPropertiesTimesliceMetric.md new file mode 100644 index 000000000..060553a65 --- /dev/null +++ b/generated/slo/docs/IndicatorPropertiesTimesliceMetric.md @@ -0,0 +1,72 @@ +# IndicatorPropertiesTimesliceMetric + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Params** | [**IndicatorPropertiesTimesliceMetricParams**](IndicatorPropertiesTimesliceMetricParams.md) | | +**Type** | **string** | The type of indicator. | + +## Methods + +### NewIndicatorPropertiesTimesliceMetric + +`func NewIndicatorPropertiesTimesliceMetric(params IndicatorPropertiesTimesliceMetricParams, type_ string, ) *IndicatorPropertiesTimesliceMetric` + +NewIndicatorPropertiesTimesliceMetric instantiates a new IndicatorPropertiesTimesliceMetric object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewIndicatorPropertiesTimesliceMetricWithDefaults + +`func NewIndicatorPropertiesTimesliceMetricWithDefaults() *IndicatorPropertiesTimesliceMetric` + +NewIndicatorPropertiesTimesliceMetricWithDefaults instantiates a new IndicatorPropertiesTimesliceMetric object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetParams + +`func (o *IndicatorPropertiesTimesliceMetric) GetParams() IndicatorPropertiesTimesliceMetricParams` + +GetParams returns the Params field if non-nil, zero value otherwise. + +### GetParamsOk + +`func (o *IndicatorPropertiesTimesliceMetric) GetParamsOk() (*IndicatorPropertiesTimesliceMetricParams, bool)` + +GetParamsOk returns a tuple with the Params field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetParams + +`func (o *IndicatorPropertiesTimesliceMetric) SetParams(v IndicatorPropertiesTimesliceMetricParams)` + +SetParams sets Params field to given value. + + +### GetType + +`func (o *IndicatorPropertiesTimesliceMetric) GetType() string` + +GetType returns the Type field if non-nil, zero value otherwise. + +### GetTypeOk + +`func (o *IndicatorPropertiesTimesliceMetric) GetTypeOk() (*string, bool)` + +GetTypeOk returns a tuple with the Type field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetType + +`func (o *IndicatorPropertiesTimesliceMetric) SetType(v string)` + +SetType sets Type field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/generated/slo/docs/IndicatorPropertiesTimesliceMetricParams.md b/generated/slo/docs/IndicatorPropertiesTimesliceMetricParams.md new file mode 100644 index 000000000..ad08d9256 --- /dev/null +++ b/generated/slo/docs/IndicatorPropertiesTimesliceMetricParams.md @@ -0,0 +1,119 @@ +# IndicatorPropertiesTimesliceMetricParams + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Index** | **string** | The index or index pattern to use | +**Filter** | Pointer to **string** | the KQL query to filter the documents with. | [optional] +**TimestampField** | **string** | The timestamp field used in the source indice. | +**Metric** | [**IndicatorPropertiesTimesliceMetricParamsMetric**](IndicatorPropertiesTimesliceMetricParamsMetric.md) | | + +## Methods + +### NewIndicatorPropertiesTimesliceMetricParams + +`func NewIndicatorPropertiesTimesliceMetricParams(index string, timestampField string, metric IndicatorPropertiesTimesliceMetricParamsMetric, ) *IndicatorPropertiesTimesliceMetricParams` + +NewIndicatorPropertiesTimesliceMetricParams instantiates a new IndicatorPropertiesTimesliceMetricParams object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewIndicatorPropertiesTimesliceMetricParamsWithDefaults + +`func NewIndicatorPropertiesTimesliceMetricParamsWithDefaults() *IndicatorPropertiesTimesliceMetricParams` + +NewIndicatorPropertiesTimesliceMetricParamsWithDefaults instantiates a new IndicatorPropertiesTimesliceMetricParams object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetIndex + +`func (o *IndicatorPropertiesTimesliceMetricParams) GetIndex() string` + +GetIndex returns the Index field if non-nil, zero value otherwise. + +### GetIndexOk + +`func (o *IndicatorPropertiesTimesliceMetricParams) GetIndexOk() (*string, bool)` + +GetIndexOk returns a tuple with the Index field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetIndex + +`func (o *IndicatorPropertiesTimesliceMetricParams) SetIndex(v string)` + +SetIndex sets Index field to given value. + + +### GetFilter + +`func (o *IndicatorPropertiesTimesliceMetricParams) GetFilter() string` + +GetFilter returns the Filter field if non-nil, zero value otherwise. + +### GetFilterOk + +`func (o *IndicatorPropertiesTimesliceMetricParams) GetFilterOk() (*string, bool)` + +GetFilterOk returns a tuple with the Filter field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetFilter + +`func (o *IndicatorPropertiesTimesliceMetricParams) SetFilter(v string)` + +SetFilter sets Filter field to given value. + +### HasFilter + +`func (o *IndicatorPropertiesTimesliceMetricParams) HasFilter() bool` + +HasFilter returns a boolean if a field has been set. + +### GetTimestampField + +`func (o *IndicatorPropertiesTimesliceMetricParams) GetTimestampField() string` + +GetTimestampField returns the TimestampField field if non-nil, zero value otherwise. + +### GetTimestampFieldOk + +`func (o *IndicatorPropertiesTimesliceMetricParams) GetTimestampFieldOk() (*string, bool)` + +GetTimestampFieldOk returns a tuple with the TimestampField field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTimestampField + +`func (o *IndicatorPropertiesTimesliceMetricParams) SetTimestampField(v string)` + +SetTimestampField sets TimestampField field to given value. + + +### GetMetric + +`func (o *IndicatorPropertiesTimesliceMetricParams) GetMetric() IndicatorPropertiesTimesliceMetricParamsMetric` + +GetMetric returns the Metric field if non-nil, zero value otherwise. + +### GetMetricOk + +`func (o *IndicatorPropertiesTimesliceMetricParams) GetMetricOk() (*IndicatorPropertiesTimesliceMetricParamsMetric, bool)` + +GetMetricOk returns a tuple with the Metric field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetMetric + +`func (o *IndicatorPropertiesTimesliceMetricParams) SetMetric(v IndicatorPropertiesTimesliceMetricParamsMetric)` + +SetMetric sets Metric field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/generated/slo/docs/IndicatorPropertiesTimesliceMetricParamsMetric.md b/generated/slo/docs/IndicatorPropertiesTimesliceMetricParamsMetric.md new file mode 100644 index 000000000..ef5db5a51 --- /dev/null +++ b/generated/slo/docs/IndicatorPropertiesTimesliceMetricParamsMetric.md @@ -0,0 +1,114 @@ +# IndicatorPropertiesTimesliceMetricParamsMetric + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Metrics** | [**[]IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner**](IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner.md) | List of metrics with their name, aggregation type, and field. | +**Equation** | **string** | The equation to calculate the metric. | +**Comparator** | **string** | The comparator to use to compare the equation to the threshold. | +**Threshold** | **float64** | The threshold used to determine if the metric is a good slice or not. | + +## Methods + +### NewIndicatorPropertiesTimesliceMetricParamsMetric + +`func NewIndicatorPropertiesTimesliceMetricParamsMetric(metrics []IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner, equation string, comparator string, threshold float64, ) *IndicatorPropertiesTimesliceMetricParamsMetric` + +NewIndicatorPropertiesTimesliceMetricParamsMetric instantiates a new IndicatorPropertiesTimesliceMetricParamsMetric object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewIndicatorPropertiesTimesliceMetricParamsMetricWithDefaults + +`func NewIndicatorPropertiesTimesliceMetricParamsMetricWithDefaults() *IndicatorPropertiesTimesliceMetricParamsMetric` + +NewIndicatorPropertiesTimesliceMetricParamsMetricWithDefaults instantiates a new IndicatorPropertiesTimesliceMetricParamsMetric object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetMetrics + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetric) GetMetrics() []IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner` + +GetMetrics returns the Metrics field if non-nil, zero value otherwise. + +### GetMetricsOk + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetric) GetMetricsOk() (*[]IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner, bool)` + +GetMetricsOk returns a tuple with the Metrics field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetMetrics + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetric) SetMetrics(v []IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner)` + +SetMetrics sets Metrics field to given value. + + +### GetEquation + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetric) GetEquation() string` + +GetEquation returns the Equation field if non-nil, zero value otherwise. + +### GetEquationOk + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetric) GetEquationOk() (*string, bool)` + +GetEquationOk returns a tuple with the Equation field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetEquation + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetric) SetEquation(v string)` + +SetEquation sets Equation field to given value. + + +### GetComparator + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetric) GetComparator() string` + +GetComparator returns the Comparator field if non-nil, zero value otherwise. + +### GetComparatorOk + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetric) GetComparatorOk() (*string, bool)` + +GetComparatorOk returns a tuple with the Comparator field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetComparator + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetric) SetComparator(v string)` + +SetComparator sets Comparator field to given value. + + +### GetThreshold + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetric) GetThreshold() float64` + +GetThreshold returns the Threshold field if non-nil, zero value otherwise. + +### GetThresholdOk + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetric) GetThresholdOk() (*float64, bool)` + +GetThresholdOk returns a tuple with the Threshold field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetThreshold + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetric) SetThreshold(v float64)` + +SetThreshold sets Threshold field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/generated/slo/docs/IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner.md b/generated/slo/docs/IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner.md new file mode 100644 index 000000000..876ee2a52 --- /dev/null +++ b/generated/slo/docs/IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner.md @@ -0,0 +1,140 @@ +# IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | The name of the metric. Only valid options are A-Z | +**Aggregation** | **string** | The aggregation type of the metric. Only valid option is \"doc_count\" | +**Field** | **string** | The field of the metric. | +**Filter** | Pointer to **string** | The filter to apply to the metric. | [optional] +**Percentile** | **float64** | The percentile value. | + +## Methods + +### NewIndicatorPropertiesTimesliceMetricParamsMetricMetricsInner + +`func NewIndicatorPropertiesTimesliceMetricParamsMetricMetricsInner(name string, aggregation string, field string, percentile float64, ) *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner` + +NewIndicatorPropertiesTimesliceMetricParamsMetricMetricsInner instantiates a new IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewIndicatorPropertiesTimesliceMetricParamsMetricMetricsInnerWithDefaults + +`func NewIndicatorPropertiesTimesliceMetricParamsMetricMetricsInnerWithDefaults() *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner` + +NewIndicatorPropertiesTimesliceMetricParamsMetricMetricsInnerWithDefaults instantiates a new IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetName + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) GetName() string` + +GetName returns the Name field if non-nil, zero value otherwise. + +### GetNameOk + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) GetNameOk() (*string, bool)` + +GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetName + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) SetName(v string)` + +SetName sets Name field to given value. + + +### GetAggregation + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) GetAggregation() string` + +GetAggregation returns the Aggregation field if non-nil, zero value otherwise. + +### GetAggregationOk + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) GetAggregationOk() (*string, bool)` + +GetAggregationOk returns a tuple with the Aggregation field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetAggregation + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) SetAggregation(v string)` + +SetAggregation sets Aggregation field to given value. + + +### GetField + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) GetField() string` + +GetField returns the Field field if non-nil, zero value otherwise. + +### GetFieldOk + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) GetFieldOk() (*string, bool)` + +GetFieldOk returns a tuple with the Field field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetField + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) SetField(v string)` + +SetField sets Field field to given value. + + +### GetFilter + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) GetFilter() string` + +GetFilter returns the Filter field if non-nil, zero value otherwise. + +### GetFilterOk + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) GetFilterOk() (*string, bool)` + +GetFilterOk returns a tuple with the Filter field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetFilter + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) SetFilter(v string)` + +SetFilter sets Filter field to given value. + +### HasFilter + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) HasFilter() bool` + +HasFilter returns a boolean if a field has been set. + +### GetPercentile + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) GetPercentile() float64` + +GetPercentile returns the Percentile field if non-nil, zero value otherwise. + +### GetPercentileOk + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) GetPercentileOk() (*float64, bool)` + +GetPercentileOk returns a tuple with the Percentile field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetPercentile + +`func (o *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) SetPercentile(v float64)` + +SetPercentile sets Percentile field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/generated/slo/docs/SloApi.md b/generated/slo/docs/SloApi.md index 1a9803832..7297aeebf 100644 --- a/generated/slo/docs/SloApi.md +++ b/generated/slo/docs/SloApi.md @@ -5,6 +5,7 @@ All URIs are relative to *http://localhost:5601* Method | HTTP request | Description ------------- | ------------- | ------------- [**CreateSloOp**](SloAPI.md#CreateSloOp) | **Post** /s/{spaceId}/api/observability/slos | Creates an SLO. +[**DeleteSloInstancesOp**](SloAPI.md#DeleteSloInstancesOp) | **Post** /s/{spaceId}/api/observability/slos/_delete_instances | Batch delete rollup and summary data for the matching list of sloId and instanceId [**DeleteSloOp**](SloAPI.md#DeleteSloOp) | **Delete** /s/{spaceId}/api/observability/slos/{sloId} | Deletes an SLO [**DisableSloOp**](SloAPI.md#DisableSloOp) | **Post** /s/{spaceId}/api/observability/slos/{sloId}/disable | Disables an SLO [**EnableSloOp**](SloAPI.md#EnableSloOp) | **Post** /s/{spaceId}/api/observability/slos/{sloId}/enable | Enables an SLO @@ -89,6 +90,78 @@ Name | Type | Description | Notes [[Back to README]](../README.md) +## DeleteSloInstancesOp + +> DeleteSloInstancesOp(ctx, spaceId).KbnXsrf(kbnXsrf).DeleteSloInstancesRequest(deleteSloInstancesRequest).Execute() + +Batch delete rollup and summary data for the matching list of sloId and instanceId + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/elastic/terraform-provider-elasticstack/slo" +) + +func main() { + kbnXsrf := "kbnXsrf_example" // string | Cross-site request forgery protection + spaceId := "default" // string | An identifier for the space. If `/s/` and the identifier are omitted from the path, the default space is used. + deleteSloInstancesRequest := *openapiclient.NewDeleteSloInstancesRequest([]openapiclient.DeleteSloInstancesRequestListInner{*openapiclient.NewDeleteSloInstancesRequestListInner("8853df00-ae2e-11ed-90af-09bb6422b258", "8853df00-ae2e-11ed-90af-09bb6422b258")}) // DeleteSloInstancesRequest | + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.SloAPI.DeleteSloInstancesOp(context.Background(), spaceId).KbnXsrf(kbnXsrf).DeleteSloInstancesRequest(deleteSloInstancesRequest).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `SloAPI.DeleteSloInstancesOp``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**spaceId** | **string** | An identifier for the space. If `/s/` and the identifier are omitted from the path, the default space is used. | + +### Other Parameters + +Other parameters are passed through a pointer to a apiDeleteSloInstancesOpRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **kbnXsrf** | **string** | Cross-site request forgery protection | + + **deleteSloInstancesRequest** | [**DeleteSloInstancesRequest**](DeleteSloInstancesRequest.md) | | + +### Return type + + (empty response body) + +### Authorization + +[basicAuth](../README.md#basicAuth), [apiKeyAuth](../README.md#apiKeyAuth) + +### HTTP request headers + +- **Content-Type**: application/json +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + ## DeleteSloOp > DeleteSloOp(ctx, spaceId, sloId).KbnXsrf(kbnXsrf).Execute() diff --git a/generated/slo/docs/SloResponse.md b/generated/slo/docs/SloResponse.md index 18d44159b..b3a1d6bda 100644 --- a/generated/slo/docs/SloResponse.md +++ b/generated/slo/docs/SloResponse.md @@ -17,6 +17,7 @@ Name | Type | Description | Notes **Enabled** | **bool** | Indicate if the SLO is enabled | **GroupBy** | **string** | optional group by field to use to generate an SLO per distinct value | **InstanceId** | **string** | the value derived from the groupBy field, if present, otherwise '*' | +**Tags** | **[]string** | List of tags | **CreatedAt** | **string** | The creation date | **UpdatedAt** | **string** | The last update date | @@ -24,7 +25,7 @@ Name | Type | Description | Notes ### NewSloResponse -`func NewSloResponse(id string, name string, description string, indicator SloResponseIndicator, timeWindow TimeWindow, budgetingMethod BudgetingMethod, objective Objective, settings Settings, revision float64, summary Summary, enabled bool, groupBy string, instanceId string, createdAt string, updatedAt string, ) *SloResponse` +`func NewSloResponse(id string, name string, description string, indicator SloResponseIndicator, timeWindow TimeWindow, budgetingMethod BudgetingMethod, objective Objective, settings Settings, revision float64, summary Summary, enabled bool, groupBy string, instanceId string, tags []string, createdAt string, updatedAt string, ) *SloResponse` NewSloResponse instantiates a new SloResponse object This constructor will assign default values to properties that have it defined, @@ -299,6 +300,26 @@ and a boolean to check if the value has been set. SetInstanceId sets InstanceId field to given value. +### GetTags + +`func (o *SloResponse) GetTags() []string` + +GetTags returns the Tags field if non-nil, zero value otherwise. + +### GetTagsOk + +`func (o *SloResponse) GetTagsOk() (*[]string, bool)` + +GetTagsOk returns a tuple with the Tags field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTags + +`func (o *SloResponse) SetTags(v []string)` + +SetTags sets Tags field to given value. + + ### GetCreatedAt `func (o *SloResponse) GetCreatedAt() string` diff --git a/generated/slo/docs/SloResponseIndicator.md b/generated/slo/docs/SloResponseIndicator.md index 544a78320..0f3ea7851 100644 --- a/generated/slo/docs/SloResponseIndicator.md +++ b/generated/slo/docs/SloResponseIndicator.md @@ -4,14 +4,14 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**Params** | [**IndicatorPropertiesHistogramParams**](IndicatorPropertiesHistogramParams.md) | | +**Params** | [**IndicatorPropertiesTimesliceMetricParams**](IndicatorPropertiesTimesliceMetricParams.md) | | **Type** | **string** | The type of indicator. | ## Methods ### NewSloResponseIndicator -`func NewSloResponseIndicator(params IndicatorPropertiesHistogramParams, type_ string, ) *SloResponseIndicator` +`func NewSloResponseIndicator(params IndicatorPropertiesTimesliceMetricParams, type_ string, ) *SloResponseIndicator` NewSloResponseIndicator instantiates a new SloResponseIndicator object This constructor will assign default values to properties that have it defined, @@ -28,20 +28,20 @@ but it doesn't guarantee that properties required by API are set ### GetParams -`func (o *SloResponseIndicator) GetParams() IndicatorPropertiesHistogramParams` +`func (o *SloResponseIndicator) GetParams() IndicatorPropertiesTimesliceMetricParams` GetParams returns the Params field if non-nil, zero value otherwise. ### GetParamsOk -`func (o *SloResponseIndicator) GetParamsOk() (*IndicatorPropertiesHistogramParams, bool)` +`func (o *SloResponseIndicator) GetParamsOk() (*IndicatorPropertiesTimesliceMetricParams, bool)` GetParamsOk returns a tuple with the Params field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetParams -`func (o *SloResponseIndicator) SetParams(v IndicatorPropertiesHistogramParams)` +`func (o *SloResponseIndicator) SetParams(v IndicatorPropertiesTimesliceMetricParams)` SetParams sets Params field to given value. diff --git a/generated/slo/docs/TimesliceMetricBasicMetricWithField.md b/generated/slo/docs/TimesliceMetricBasicMetricWithField.md new file mode 100644 index 000000000..8f3b920b4 --- /dev/null +++ b/generated/slo/docs/TimesliceMetricBasicMetricWithField.md @@ -0,0 +1,119 @@ +# TimesliceMetricBasicMetricWithField + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | The name of the metric. Only valid options are A-Z | +**Aggregation** | **string** | The aggregation type of the metric. | +**Field** | **string** | The field of the metric. | +**Filter** | Pointer to **string** | The filter to apply to the metric. | [optional] + +## Methods + +### NewTimesliceMetricBasicMetricWithField + +`func NewTimesliceMetricBasicMetricWithField(name string, aggregation string, field string, ) *TimesliceMetricBasicMetricWithField` + +NewTimesliceMetricBasicMetricWithField instantiates a new TimesliceMetricBasicMetricWithField object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewTimesliceMetricBasicMetricWithFieldWithDefaults + +`func NewTimesliceMetricBasicMetricWithFieldWithDefaults() *TimesliceMetricBasicMetricWithField` + +NewTimesliceMetricBasicMetricWithFieldWithDefaults instantiates a new TimesliceMetricBasicMetricWithField object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetName + +`func (o *TimesliceMetricBasicMetricWithField) GetName() string` + +GetName returns the Name field if non-nil, zero value otherwise. + +### GetNameOk + +`func (o *TimesliceMetricBasicMetricWithField) GetNameOk() (*string, bool)` + +GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetName + +`func (o *TimesliceMetricBasicMetricWithField) SetName(v string)` + +SetName sets Name field to given value. + + +### GetAggregation + +`func (o *TimesliceMetricBasicMetricWithField) GetAggregation() string` + +GetAggregation returns the Aggregation field if non-nil, zero value otherwise. + +### GetAggregationOk + +`func (o *TimesliceMetricBasicMetricWithField) GetAggregationOk() (*string, bool)` + +GetAggregationOk returns a tuple with the Aggregation field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetAggregation + +`func (o *TimesliceMetricBasicMetricWithField) SetAggregation(v string)` + +SetAggregation sets Aggregation field to given value. + + +### GetField + +`func (o *TimesliceMetricBasicMetricWithField) GetField() string` + +GetField returns the Field field if non-nil, zero value otherwise. + +### GetFieldOk + +`func (o *TimesliceMetricBasicMetricWithField) GetFieldOk() (*string, bool)` + +GetFieldOk returns a tuple with the Field field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetField + +`func (o *TimesliceMetricBasicMetricWithField) SetField(v string)` + +SetField sets Field field to given value. + + +### GetFilter + +`func (o *TimesliceMetricBasicMetricWithField) GetFilter() string` + +GetFilter returns the Filter field if non-nil, zero value otherwise. + +### GetFilterOk + +`func (o *TimesliceMetricBasicMetricWithField) GetFilterOk() (*string, bool)` + +GetFilterOk returns a tuple with the Filter field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetFilter + +`func (o *TimesliceMetricBasicMetricWithField) SetFilter(v string)` + +SetFilter sets Filter field to given value. + +### HasFilter + +`func (o *TimesliceMetricBasicMetricWithField) HasFilter() bool` + +HasFilter returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/generated/slo/docs/TimesliceMetricDocCountMetric.md b/generated/slo/docs/TimesliceMetricDocCountMetric.md new file mode 100644 index 000000000..fec89756e --- /dev/null +++ b/generated/slo/docs/TimesliceMetricDocCountMetric.md @@ -0,0 +1,98 @@ +# TimesliceMetricDocCountMetric + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | The name of the metric. Only valid options are A-Z | +**Aggregation** | **string** | The aggregation type of the metric. Only valid option is \"doc_count\" | +**Filter** | Pointer to **string** | The filter to apply to the metric. | [optional] + +## Methods + +### NewTimesliceMetricDocCountMetric + +`func NewTimesliceMetricDocCountMetric(name string, aggregation string, ) *TimesliceMetricDocCountMetric` + +NewTimesliceMetricDocCountMetric instantiates a new TimesliceMetricDocCountMetric object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewTimesliceMetricDocCountMetricWithDefaults + +`func NewTimesliceMetricDocCountMetricWithDefaults() *TimesliceMetricDocCountMetric` + +NewTimesliceMetricDocCountMetricWithDefaults instantiates a new TimesliceMetricDocCountMetric object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetName + +`func (o *TimesliceMetricDocCountMetric) GetName() string` + +GetName returns the Name field if non-nil, zero value otherwise. + +### GetNameOk + +`func (o *TimesliceMetricDocCountMetric) GetNameOk() (*string, bool)` + +GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetName + +`func (o *TimesliceMetricDocCountMetric) SetName(v string)` + +SetName sets Name field to given value. + + +### GetAggregation + +`func (o *TimesliceMetricDocCountMetric) GetAggregation() string` + +GetAggregation returns the Aggregation field if non-nil, zero value otherwise. + +### GetAggregationOk + +`func (o *TimesliceMetricDocCountMetric) GetAggregationOk() (*string, bool)` + +GetAggregationOk returns a tuple with the Aggregation field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetAggregation + +`func (o *TimesliceMetricDocCountMetric) SetAggregation(v string)` + +SetAggregation sets Aggregation field to given value. + + +### GetFilter + +`func (o *TimesliceMetricDocCountMetric) GetFilter() string` + +GetFilter returns the Filter field if non-nil, zero value otherwise. + +### GetFilterOk + +`func (o *TimesliceMetricDocCountMetric) GetFilterOk() (*string, bool)` + +GetFilterOk returns a tuple with the Filter field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetFilter + +`func (o *TimesliceMetricDocCountMetric) SetFilter(v string)` + +SetFilter sets Filter field to given value. + +### HasFilter + +`func (o *TimesliceMetricDocCountMetric) HasFilter() bool` + +HasFilter returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/generated/slo/docs/TimesliceMetricPercentileMetric.md b/generated/slo/docs/TimesliceMetricPercentileMetric.md new file mode 100644 index 000000000..2b873b06d --- /dev/null +++ b/generated/slo/docs/TimesliceMetricPercentileMetric.md @@ -0,0 +1,140 @@ +# TimesliceMetricPercentileMetric + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | The name of the metric. Only valid options are A-Z | +**Aggregation** | **string** | The aggregation type of the metric. Only valid option is \"percentile\" | +**Field** | **string** | The field of the metric. | +**Percentile** | **float64** | The percentile value. | +**Filter** | Pointer to **string** | The filter to apply to the metric. | [optional] + +## Methods + +### NewTimesliceMetricPercentileMetric + +`func NewTimesliceMetricPercentileMetric(name string, aggregation string, field string, percentile float64, ) *TimesliceMetricPercentileMetric` + +NewTimesliceMetricPercentileMetric instantiates a new TimesliceMetricPercentileMetric object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewTimesliceMetricPercentileMetricWithDefaults + +`func NewTimesliceMetricPercentileMetricWithDefaults() *TimesliceMetricPercentileMetric` + +NewTimesliceMetricPercentileMetricWithDefaults instantiates a new TimesliceMetricPercentileMetric object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetName + +`func (o *TimesliceMetricPercentileMetric) GetName() string` + +GetName returns the Name field if non-nil, zero value otherwise. + +### GetNameOk + +`func (o *TimesliceMetricPercentileMetric) GetNameOk() (*string, bool)` + +GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetName + +`func (o *TimesliceMetricPercentileMetric) SetName(v string)` + +SetName sets Name field to given value. + + +### GetAggregation + +`func (o *TimesliceMetricPercentileMetric) GetAggregation() string` + +GetAggregation returns the Aggregation field if non-nil, zero value otherwise. + +### GetAggregationOk + +`func (o *TimesliceMetricPercentileMetric) GetAggregationOk() (*string, bool)` + +GetAggregationOk returns a tuple with the Aggregation field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetAggregation + +`func (o *TimesliceMetricPercentileMetric) SetAggregation(v string)` + +SetAggregation sets Aggregation field to given value. + + +### GetField + +`func (o *TimesliceMetricPercentileMetric) GetField() string` + +GetField returns the Field field if non-nil, zero value otherwise. + +### GetFieldOk + +`func (o *TimesliceMetricPercentileMetric) GetFieldOk() (*string, bool)` + +GetFieldOk returns a tuple with the Field field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetField + +`func (o *TimesliceMetricPercentileMetric) SetField(v string)` + +SetField sets Field field to given value. + + +### GetPercentile + +`func (o *TimesliceMetricPercentileMetric) GetPercentile() float64` + +GetPercentile returns the Percentile field if non-nil, zero value otherwise. + +### GetPercentileOk + +`func (o *TimesliceMetricPercentileMetric) GetPercentileOk() (*float64, bool)` + +GetPercentileOk returns a tuple with the Percentile field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetPercentile + +`func (o *TimesliceMetricPercentileMetric) SetPercentile(v float64)` + +SetPercentile sets Percentile field to given value. + + +### GetFilter + +`func (o *TimesliceMetricPercentileMetric) GetFilter() string` + +GetFilter returns the Filter field if non-nil, zero value otherwise. + +### GetFilterOk + +`func (o *TimesliceMetricPercentileMetric) GetFilterOk() (*string, bool)` + +GetFilterOk returns a tuple with the Filter field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetFilter + +`func (o *TimesliceMetricPercentileMetric) SetFilter(v string)` + +SetFilter sets Filter field to given value. + +### HasFilter + +`func (o *TimesliceMetricPercentileMetric) HasFilter() bool` + +HasFilter returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/generated/slo/docs/UpdateSloRequest.md b/generated/slo/docs/UpdateSloRequest.md index e228b7e32..31065689a 100644 --- a/generated/slo/docs/UpdateSloRequest.md +++ b/generated/slo/docs/UpdateSloRequest.md @@ -11,6 +11,7 @@ Name | Type | Description | Notes **BudgetingMethod** | Pointer to [**BudgetingMethod**](BudgetingMethod.md) | | [optional] **Objective** | Pointer to [**Objective**](Objective.md) | | [optional] **Settings** | Pointer to [**Settings**](Settings.md) | | [optional] +**Tags** | Pointer to **[]string** | List of tags | [optional] ## Methods @@ -206,6 +207,31 @@ SetSettings sets Settings field to given value. HasSettings returns a boolean if a field has been set. +### GetTags + +`func (o *UpdateSloRequest) GetTags() []string` + +GetTags returns the Tags field if non-nil, zero value otherwise. + +### GetTagsOk + +`func (o *UpdateSloRequest) GetTagsOk() (*[]string, bool)` + +GetTagsOk returns a tuple with the Tags field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTags + +`func (o *UpdateSloRequest) SetTags(v []string)` + +SetTags sets Tags field to given value. + +### HasTags + +`func (o *UpdateSloRequest) HasTags() bool` + +HasTags returns a boolean if a field has been set. + [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/generated/slo/model_create_slo_request.go b/generated/slo/model_create_slo_request.go index 9b14cb3fa..b96f904a4 100644 --- a/generated/slo/model_create_slo_request.go +++ b/generated/slo/model_create_slo_request.go @@ -32,6 +32,8 @@ type CreateSloRequest struct { Settings *Settings `json:"settings,omitempty"` // optional group by field to use to generate an SLO per distinct value GroupBy *string `json:"groupBy,omitempty"` + // List of tags + Tags []string `json:"tags,omitempty"` } // NewCreateSloRequest instantiates a new CreateSloRequest object @@ -297,6 +299,38 @@ func (o *CreateSloRequest) SetGroupBy(v string) { o.GroupBy = &v } +// GetTags returns the Tags field value if set, zero value otherwise. +func (o *CreateSloRequest) GetTags() []string { + if o == nil || IsNil(o.Tags) { + var ret []string + return ret + } + return o.Tags +} + +// GetTagsOk returns a tuple with the Tags field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *CreateSloRequest) GetTagsOk() ([]string, bool) { + if o == nil || IsNil(o.Tags) { + return nil, false + } + return o.Tags, true +} + +// HasTags returns a boolean if a field has been set. +func (o *CreateSloRequest) HasTags() bool { + if o != nil && !IsNil(o.Tags) { + return true + } + + return false +} + +// SetTags gets a reference to the given []string and assigns it to the Tags field. +func (o *CreateSloRequest) SetTags(v []string) { + o.Tags = v +} + func (o CreateSloRequest) MarshalJSON() ([]byte, error) { toSerialize, err := o.ToMap() if err != nil { @@ -322,6 +356,9 @@ func (o CreateSloRequest) ToMap() (map[string]interface{}, error) { if !IsNil(o.GroupBy) { toSerialize["groupBy"] = o.GroupBy } + if !IsNil(o.Tags) { + toSerialize["tags"] = o.Tags + } return toSerialize, nil } diff --git a/generated/slo/model_create_slo_request_indicator.go b/generated/slo/model_create_slo_request_indicator.go index 1ad246ded..56c4975b2 100644 --- a/generated/slo/model_create_slo_request_indicator.go +++ b/generated/slo/model_create_slo_request_indicator.go @@ -22,6 +22,7 @@ type CreateSloRequestIndicator struct { IndicatorPropertiesCustomKql *IndicatorPropertiesCustomKql IndicatorPropertiesCustomMetric *IndicatorPropertiesCustomMetric IndicatorPropertiesHistogram *IndicatorPropertiesHistogram + IndicatorPropertiesTimesliceMetric *IndicatorPropertiesTimesliceMetric } // IndicatorPropertiesApmAvailabilityAsCreateSloRequestIndicator is a convenience function that returns IndicatorPropertiesApmAvailability wrapped in CreateSloRequestIndicator @@ -59,6 +60,13 @@ func IndicatorPropertiesHistogramAsCreateSloRequestIndicator(v *IndicatorPropert } } +// IndicatorPropertiesTimesliceMetricAsCreateSloRequestIndicator is a convenience function that returns IndicatorPropertiesTimesliceMetric wrapped in CreateSloRequestIndicator +func IndicatorPropertiesTimesliceMetricAsCreateSloRequestIndicator(v *IndicatorPropertiesTimesliceMetric) CreateSloRequestIndicator { + return CreateSloRequestIndicator{ + IndicatorPropertiesTimesliceMetric: v, + } +} + // Unmarshal JSON data into one of the pointers in the struct func (dst *CreateSloRequestIndicator) UnmarshalJSON(data []byte) error { var err error @@ -128,6 +136,19 @@ func (dst *CreateSloRequestIndicator) UnmarshalJSON(data []byte) error { dst.IndicatorPropertiesHistogram = nil } + // try to unmarshal data into IndicatorPropertiesTimesliceMetric + err = json.Unmarshal(data, &dst.IndicatorPropertiesTimesliceMetric) + if err == nil { + jsonIndicatorPropertiesTimesliceMetric, _ := json.Marshal(dst.IndicatorPropertiesTimesliceMetric) + if string(jsonIndicatorPropertiesTimesliceMetric) == "{}" { // empty struct + dst.IndicatorPropertiesTimesliceMetric = nil + } else { + match++ + } + } else { + dst.IndicatorPropertiesTimesliceMetric = nil + } + if match > 1 { // more than 1 match // reset to nil dst.IndicatorPropertiesApmAvailability = nil @@ -135,6 +156,7 @@ func (dst *CreateSloRequestIndicator) UnmarshalJSON(data []byte) error { dst.IndicatorPropertiesCustomKql = nil dst.IndicatorPropertiesCustomMetric = nil dst.IndicatorPropertiesHistogram = nil + dst.IndicatorPropertiesTimesliceMetric = nil return fmt.Errorf("data matches more than one schema in oneOf(CreateSloRequestIndicator)") } else if match == 1 { @@ -166,6 +188,10 @@ func (src CreateSloRequestIndicator) MarshalJSON() ([]byte, error) { return json.Marshal(&src.IndicatorPropertiesHistogram) } + if src.IndicatorPropertiesTimesliceMetric != nil { + return json.Marshal(&src.IndicatorPropertiesTimesliceMetric) + } + return nil, nil // no data in oneOf schemas } @@ -194,6 +220,10 @@ func (obj *CreateSloRequestIndicator) GetActualInstance() interface{} { return obj.IndicatorPropertiesHistogram } + if obj.IndicatorPropertiesTimesliceMetric != nil { + return obj.IndicatorPropertiesTimesliceMetric + } + // all schemas are nil return nil } diff --git a/generated/slo/model_delete_slo_instances_request.go b/generated/slo/model_delete_slo_instances_request.go new file mode 100644 index 000000000..a8a4be95f --- /dev/null +++ b/generated/slo/model_delete_slo_instances_request.go @@ -0,0 +1,116 @@ +/* +SLOs + +OpenAPI schema for SLOs endpoints + +API version: 1.0 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package slo + +import ( + "encoding/json" +) + +// checks if the DeleteSloInstancesRequest type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &DeleteSloInstancesRequest{} + +// DeleteSloInstancesRequest The delete SLO instances request takes a list of SLO id and instance id, then delete the rollup and summary data. This API can be used to remove the staled data of an instance SLO that no longer get updated. +type DeleteSloInstancesRequest struct { + // An array of slo id and instance id + List []DeleteSloInstancesRequestListInner `json:"list"` +} + +// NewDeleteSloInstancesRequest instantiates a new DeleteSloInstancesRequest object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewDeleteSloInstancesRequest(list []DeleteSloInstancesRequestListInner) *DeleteSloInstancesRequest { + this := DeleteSloInstancesRequest{} + this.List = list + return &this +} + +// NewDeleteSloInstancesRequestWithDefaults instantiates a new DeleteSloInstancesRequest object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewDeleteSloInstancesRequestWithDefaults() *DeleteSloInstancesRequest { + this := DeleteSloInstancesRequest{} + return &this +} + +// GetList returns the List field value +func (o *DeleteSloInstancesRequest) GetList() []DeleteSloInstancesRequestListInner { + if o == nil { + var ret []DeleteSloInstancesRequestListInner + return ret + } + + return o.List +} + +// GetListOk returns a tuple with the List field value +// and a boolean to check if the value has been set. +func (o *DeleteSloInstancesRequest) GetListOk() ([]DeleteSloInstancesRequestListInner, bool) { + if o == nil { + return nil, false + } + return o.List, true +} + +// SetList sets field value +func (o *DeleteSloInstancesRequest) SetList(v []DeleteSloInstancesRequestListInner) { + o.List = v +} + +func (o DeleteSloInstancesRequest) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o DeleteSloInstancesRequest) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["list"] = o.List + return toSerialize, nil +} + +type NullableDeleteSloInstancesRequest struct { + value *DeleteSloInstancesRequest + isSet bool +} + +func (v NullableDeleteSloInstancesRequest) Get() *DeleteSloInstancesRequest { + return v.value +} + +func (v *NullableDeleteSloInstancesRequest) Set(val *DeleteSloInstancesRequest) { + v.value = val + v.isSet = true +} + +func (v NullableDeleteSloInstancesRequest) IsSet() bool { + return v.isSet +} + +func (v *NullableDeleteSloInstancesRequest) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableDeleteSloInstancesRequest(val *DeleteSloInstancesRequest) *NullableDeleteSloInstancesRequest { + return &NullableDeleteSloInstancesRequest{value: val, isSet: true} +} + +func (v NullableDeleteSloInstancesRequest) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableDeleteSloInstancesRequest) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/generated/slo/model_delete_slo_instances_request_list_inner.go b/generated/slo/model_delete_slo_instances_request_list_inner.go new file mode 100644 index 000000000..22694c856 --- /dev/null +++ b/generated/slo/model_delete_slo_instances_request_list_inner.go @@ -0,0 +1,144 @@ +/* +SLOs + +OpenAPI schema for SLOs endpoints + +API version: 1.0 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package slo + +import ( + "encoding/json" +) + +// checks if the DeleteSloInstancesRequestListInner type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &DeleteSloInstancesRequestListInner{} + +// DeleteSloInstancesRequestListInner struct for DeleteSloInstancesRequestListInner +type DeleteSloInstancesRequestListInner struct { + // The SLO unique identifier + SloId string `json:"sloId"` + // The SLO instance identifier + InstanceId string `json:"instanceId"` +} + +// NewDeleteSloInstancesRequestListInner instantiates a new DeleteSloInstancesRequestListInner object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewDeleteSloInstancesRequestListInner(sloId string, instanceId string) *DeleteSloInstancesRequestListInner { + this := DeleteSloInstancesRequestListInner{} + this.SloId = sloId + this.InstanceId = instanceId + return &this +} + +// NewDeleteSloInstancesRequestListInnerWithDefaults instantiates a new DeleteSloInstancesRequestListInner object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewDeleteSloInstancesRequestListInnerWithDefaults() *DeleteSloInstancesRequestListInner { + this := DeleteSloInstancesRequestListInner{} + return &this +} + +// GetSloId returns the SloId field value +func (o *DeleteSloInstancesRequestListInner) GetSloId() string { + if o == nil { + var ret string + return ret + } + + return o.SloId +} + +// GetSloIdOk returns a tuple with the SloId field value +// and a boolean to check if the value has been set. +func (o *DeleteSloInstancesRequestListInner) GetSloIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.SloId, true +} + +// SetSloId sets field value +func (o *DeleteSloInstancesRequestListInner) SetSloId(v string) { + o.SloId = v +} + +// GetInstanceId returns the InstanceId field value +func (o *DeleteSloInstancesRequestListInner) GetInstanceId() string { + if o == nil { + var ret string + return ret + } + + return o.InstanceId +} + +// GetInstanceIdOk returns a tuple with the InstanceId field value +// and a boolean to check if the value has been set. +func (o *DeleteSloInstancesRequestListInner) GetInstanceIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.InstanceId, true +} + +// SetInstanceId sets field value +func (o *DeleteSloInstancesRequestListInner) SetInstanceId(v string) { + o.InstanceId = v +} + +func (o DeleteSloInstancesRequestListInner) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o DeleteSloInstancesRequestListInner) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["sloId"] = o.SloId + toSerialize["instanceId"] = o.InstanceId + return toSerialize, nil +} + +type NullableDeleteSloInstancesRequestListInner struct { + value *DeleteSloInstancesRequestListInner + isSet bool +} + +func (v NullableDeleteSloInstancesRequestListInner) Get() *DeleteSloInstancesRequestListInner { + return v.value +} + +func (v *NullableDeleteSloInstancesRequestListInner) Set(val *DeleteSloInstancesRequestListInner) { + v.value = val + v.isSet = true +} + +func (v NullableDeleteSloInstancesRequestListInner) IsSet() bool { + return v.isSet +} + +func (v *NullableDeleteSloInstancesRequestListInner) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableDeleteSloInstancesRequestListInner(val *DeleteSloInstancesRequestListInner) *NullableDeleteSloInstancesRequestListInner { + return &NullableDeleteSloInstancesRequestListInner{value: val, isSet: true} +} + +func (v NullableDeleteSloInstancesRequestListInner) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableDeleteSloInstancesRequestListInner) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/generated/slo/model_historical_summary_request.go b/generated/slo/model_historical_summary_request.go index 6d522dc18..a06576baa 100644 --- a/generated/slo/model_historical_summary_request.go +++ b/generated/slo/model_historical_summary_request.go @@ -20,16 +20,16 @@ var _ MappedNullable = &HistoricalSummaryRequest{} // HistoricalSummaryRequest struct for HistoricalSummaryRequest type HistoricalSummaryRequest struct { // The list of SLO identifiers to get the historical summary for - SloIds []string `json:"sloIds"` + List []string `json:"list"` } // NewHistoricalSummaryRequest instantiates a new HistoricalSummaryRequest object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewHistoricalSummaryRequest(sloIds []string) *HistoricalSummaryRequest { +func NewHistoricalSummaryRequest(list []string) *HistoricalSummaryRequest { this := HistoricalSummaryRequest{} - this.SloIds = sloIds + this.List = list return &this } @@ -41,28 +41,28 @@ func NewHistoricalSummaryRequestWithDefaults() *HistoricalSummaryRequest { return &this } -// GetSloIds returns the SloIds field value -func (o *HistoricalSummaryRequest) GetSloIds() []string { +// GetList returns the List field value +func (o *HistoricalSummaryRequest) GetList() []string { if o == nil { var ret []string return ret } - return o.SloIds + return o.List } -// GetSloIdsOk returns a tuple with the SloIds field value +// GetListOk returns a tuple with the List field value // and a boolean to check if the value has been set. -func (o *HistoricalSummaryRequest) GetSloIdsOk() ([]string, bool) { +func (o *HistoricalSummaryRequest) GetListOk() ([]string, bool) { if o == nil { return nil, false } - return o.SloIds, true + return o.List, true } -// SetSloIds sets field value -func (o *HistoricalSummaryRequest) SetSloIds(v []string) { - o.SloIds = v +// SetList sets field value +func (o *HistoricalSummaryRequest) SetList(v []string) { + o.List = v } func (o HistoricalSummaryRequest) MarshalJSON() ([]byte, error) { @@ -75,7 +75,7 @@ func (o HistoricalSummaryRequest) MarshalJSON() ([]byte, error) { func (o HistoricalSummaryRequest) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - toSerialize["sloIds"] = o.SloIds + toSerialize["list"] = o.List return toSerialize, nil } diff --git a/generated/slo/model_indicator_properties_custom_kql_params.go b/generated/slo/model_indicator_properties_custom_kql_params.go index 6ca493a4c..e84d0b41d 100644 --- a/generated/slo/model_indicator_properties_custom_kql_params.go +++ b/generated/slo/model_indicator_properties_custom_kql_params.go @@ -24,9 +24,9 @@ type IndicatorPropertiesCustomKqlParams struct { // the KQL query to filter the documents with. Filter *string `json:"filter,omitempty"` // the KQL query used to define the good events. - Good *string `json:"good,omitempty"` + Good string `json:"good"` // the KQL query used to define all events. - Total *string `json:"total,omitempty"` + Total string `json:"total"` // The timestamp field used in the source indice. TimestampField string `json:"timestampField"` } @@ -35,9 +35,11 @@ type IndicatorPropertiesCustomKqlParams struct { // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewIndicatorPropertiesCustomKqlParams(index string, timestampField string) *IndicatorPropertiesCustomKqlParams { +func NewIndicatorPropertiesCustomKqlParams(index string, good string, total string, timestampField string) *IndicatorPropertiesCustomKqlParams { this := IndicatorPropertiesCustomKqlParams{} this.Index = index + this.Good = good + this.Total = total this.TimestampField = timestampField return &this } @@ -106,68 +108,52 @@ func (o *IndicatorPropertiesCustomKqlParams) SetFilter(v string) { o.Filter = &v } -// GetGood returns the Good field value if set, zero value otherwise. +// GetGood returns the Good field value func (o *IndicatorPropertiesCustomKqlParams) GetGood() string { - if o == nil || IsNil(o.Good) { + if o == nil { var ret string return ret } - return *o.Good + + return o.Good } -// GetGoodOk returns a tuple with the Good field value if set, nil otherwise +// GetGoodOk returns a tuple with the Good field value // and a boolean to check if the value has been set. func (o *IndicatorPropertiesCustomKqlParams) GetGoodOk() (*string, bool) { - if o == nil || IsNil(o.Good) { + if o == nil { return nil, false } - return o.Good, true -} - -// HasGood returns a boolean if a field has been set. -func (o *IndicatorPropertiesCustomKqlParams) HasGood() bool { - if o != nil && !IsNil(o.Good) { - return true - } - - return false + return &o.Good, true } -// SetGood gets a reference to the given string and assigns it to the Good field. +// SetGood sets field value func (o *IndicatorPropertiesCustomKqlParams) SetGood(v string) { - o.Good = &v + o.Good = v } -// GetTotal returns the Total field value if set, zero value otherwise. +// GetTotal returns the Total field value func (o *IndicatorPropertiesCustomKqlParams) GetTotal() string { - if o == nil || IsNil(o.Total) { + if o == nil { var ret string return ret } - return *o.Total + + return o.Total } -// GetTotalOk returns a tuple with the Total field value if set, nil otherwise +// GetTotalOk returns a tuple with the Total field value // and a boolean to check if the value has been set. func (o *IndicatorPropertiesCustomKqlParams) GetTotalOk() (*string, bool) { - if o == nil || IsNil(o.Total) { + if o == nil { return nil, false } - return o.Total, true -} - -// HasTotal returns a boolean if a field has been set. -func (o *IndicatorPropertiesCustomKqlParams) HasTotal() bool { - if o != nil && !IsNil(o.Total) { - return true - } - - return false + return &o.Total, true } -// SetTotal gets a reference to the given string and assigns it to the Total field. +// SetTotal sets field value func (o *IndicatorPropertiesCustomKqlParams) SetTotal(v string) { - o.Total = &v + o.Total = v } // GetTimestampField returns the TimestampField field value @@ -208,12 +194,8 @@ func (o IndicatorPropertiesCustomKqlParams) ToMap() (map[string]interface{}, err if !IsNil(o.Filter) { toSerialize["filter"] = o.Filter } - if !IsNil(o.Good) { - toSerialize["good"] = o.Good - } - if !IsNil(o.Total) { - toSerialize["total"] = o.Total - } + toSerialize["good"] = o.Good + toSerialize["total"] = o.Total toSerialize["timestampField"] = o.TimestampField return toSerialize, nil } diff --git a/generated/slo/model_indicator_properties_custom_metric_params.go b/generated/slo/model_indicator_properties_custom_metric_params.go index df4355a28..88f7cc8db 100644 --- a/generated/slo/model_indicator_properties_custom_metric_params.go +++ b/generated/slo/model_indicator_properties_custom_metric_params.go @@ -22,7 +22,7 @@ type IndicatorPropertiesCustomMetricParams struct { // The index or index pattern to use Index string `json:"index"` // the KQL query to filter the documents with. - Filter string `json:"filter"` + Filter *string `json:"filter,omitempty"` // The timestamp field used in the source indice. TimestampField string `json:"timestampField"` Good IndicatorPropertiesCustomMetricParamsGood `json:"good"` @@ -33,10 +33,9 @@ type IndicatorPropertiesCustomMetricParams struct { // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewIndicatorPropertiesCustomMetricParams(index string, filter string, timestampField string, good IndicatorPropertiesCustomMetricParamsGood, total IndicatorPropertiesCustomMetricParamsTotal) *IndicatorPropertiesCustomMetricParams { +func NewIndicatorPropertiesCustomMetricParams(index string, timestampField string, good IndicatorPropertiesCustomMetricParamsGood, total IndicatorPropertiesCustomMetricParamsTotal) *IndicatorPropertiesCustomMetricParams { this := IndicatorPropertiesCustomMetricParams{} this.Index = index - this.Filter = filter this.TimestampField = timestampField this.Good = good this.Total = total @@ -75,28 +74,36 @@ func (o *IndicatorPropertiesCustomMetricParams) SetIndex(v string) { o.Index = v } -// GetFilter returns the Filter field value +// GetFilter returns the Filter field value if set, zero value otherwise. func (o *IndicatorPropertiesCustomMetricParams) GetFilter() string { - if o == nil { + if o == nil || IsNil(o.Filter) { var ret string return ret } - - return o.Filter + return *o.Filter } -// GetFilterOk returns a tuple with the Filter field value +// GetFilterOk returns a tuple with the Filter field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *IndicatorPropertiesCustomMetricParams) GetFilterOk() (*string, bool) { - if o == nil { + if o == nil || IsNil(o.Filter) { return nil, false } - return &o.Filter, true + return o.Filter, true +} + +// HasFilter returns a boolean if a field has been set. +func (o *IndicatorPropertiesCustomMetricParams) HasFilter() bool { + if o != nil && !IsNil(o.Filter) { + return true + } + + return false } -// SetFilter sets field value +// SetFilter gets a reference to the given string and assigns it to the Filter field. func (o *IndicatorPropertiesCustomMetricParams) SetFilter(v string) { - o.Filter = v + o.Filter = &v } // GetTimestampField returns the TimestampField field value @@ -182,7 +189,9 @@ func (o IndicatorPropertiesCustomMetricParams) MarshalJSON() ([]byte, error) { func (o IndicatorPropertiesCustomMetricParams) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} toSerialize["index"] = o.Index - toSerialize["filter"] = o.Filter + if !IsNil(o.Filter) { + toSerialize["filter"] = o.Filter + } toSerialize["timestampField"] = o.TimestampField toSerialize["good"] = o.Good toSerialize["total"] = o.Total diff --git a/generated/slo/model_indicator_properties_timeslice_metric.go b/generated/slo/model_indicator_properties_timeslice_metric.go new file mode 100644 index 000000000..bd5e6fde0 --- /dev/null +++ b/generated/slo/model_indicator_properties_timeslice_metric.go @@ -0,0 +1,143 @@ +/* +SLOs + +OpenAPI schema for SLOs endpoints + +API version: 1.0 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package slo + +import ( + "encoding/json" +) + +// checks if the IndicatorPropertiesTimesliceMetric type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &IndicatorPropertiesTimesliceMetric{} + +// IndicatorPropertiesTimesliceMetric Defines properties for a timeslice metric indicator type +type IndicatorPropertiesTimesliceMetric struct { + Params IndicatorPropertiesTimesliceMetricParams `json:"params"` + // The type of indicator. + Type string `json:"type"` +} + +// NewIndicatorPropertiesTimesliceMetric instantiates a new IndicatorPropertiesTimesliceMetric object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewIndicatorPropertiesTimesliceMetric(params IndicatorPropertiesTimesliceMetricParams, type_ string) *IndicatorPropertiesTimesliceMetric { + this := IndicatorPropertiesTimesliceMetric{} + this.Params = params + this.Type = type_ + return &this +} + +// NewIndicatorPropertiesTimesliceMetricWithDefaults instantiates a new IndicatorPropertiesTimesliceMetric object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewIndicatorPropertiesTimesliceMetricWithDefaults() *IndicatorPropertiesTimesliceMetric { + this := IndicatorPropertiesTimesliceMetric{} + return &this +} + +// GetParams returns the Params field value +func (o *IndicatorPropertiesTimesliceMetric) GetParams() IndicatorPropertiesTimesliceMetricParams { + if o == nil { + var ret IndicatorPropertiesTimesliceMetricParams + return ret + } + + return o.Params +} + +// GetParamsOk returns a tuple with the Params field value +// and a boolean to check if the value has been set. +func (o *IndicatorPropertiesTimesliceMetric) GetParamsOk() (*IndicatorPropertiesTimesliceMetricParams, bool) { + if o == nil { + return nil, false + } + return &o.Params, true +} + +// SetParams sets field value +func (o *IndicatorPropertiesTimesliceMetric) SetParams(v IndicatorPropertiesTimesliceMetricParams) { + o.Params = v +} + +// GetType returns the Type field value +func (o *IndicatorPropertiesTimesliceMetric) GetType() string { + if o == nil { + var ret string + return ret + } + + return o.Type +} + +// GetTypeOk returns a tuple with the Type field value +// and a boolean to check if the value has been set. +func (o *IndicatorPropertiesTimesliceMetric) GetTypeOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Type, true +} + +// SetType sets field value +func (o *IndicatorPropertiesTimesliceMetric) SetType(v string) { + o.Type = v +} + +func (o IndicatorPropertiesTimesliceMetric) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o IndicatorPropertiesTimesliceMetric) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["params"] = o.Params + toSerialize["type"] = o.Type + return toSerialize, nil +} + +type NullableIndicatorPropertiesTimesliceMetric struct { + value *IndicatorPropertiesTimesliceMetric + isSet bool +} + +func (v NullableIndicatorPropertiesTimesliceMetric) Get() *IndicatorPropertiesTimesliceMetric { + return v.value +} + +func (v *NullableIndicatorPropertiesTimesliceMetric) Set(val *IndicatorPropertiesTimesliceMetric) { + v.value = val + v.isSet = true +} + +func (v NullableIndicatorPropertiesTimesliceMetric) IsSet() bool { + return v.isSet +} + +func (v *NullableIndicatorPropertiesTimesliceMetric) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableIndicatorPropertiesTimesliceMetric(val *IndicatorPropertiesTimesliceMetric) *NullableIndicatorPropertiesTimesliceMetric { + return &NullableIndicatorPropertiesTimesliceMetric{value: val, isSet: true} +} + +func (v NullableIndicatorPropertiesTimesliceMetric) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableIndicatorPropertiesTimesliceMetric) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/generated/slo/model_indicator_properties_timeslice_metric_params.go b/generated/slo/model_indicator_properties_timeslice_metric_params.go new file mode 100644 index 000000000..d702e10b5 --- /dev/null +++ b/generated/slo/model_indicator_properties_timeslice_metric_params.go @@ -0,0 +1,208 @@ +/* +SLOs + +OpenAPI schema for SLOs endpoints + +API version: 1.0 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package slo + +import ( + "encoding/json" +) + +// checks if the IndicatorPropertiesTimesliceMetricParams type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &IndicatorPropertiesTimesliceMetricParams{} + +// IndicatorPropertiesTimesliceMetricParams An object containing the indicator parameters. +type IndicatorPropertiesTimesliceMetricParams struct { + // The index or index pattern to use + Index string `json:"index"` + // the KQL query to filter the documents with. + Filter *string `json:"filter,omitempty"` + // The timestamp field used in the source indice. + TimestampField string `json:"timestampField"` + Metric IndicatorPropertiesTimesliceMetricParamsMetric `json:"metric"` +} + +// NewIndicatorPropertiesTimesliceMetricParams instantiates a new IndicatorPropertiesTimesliceMetricParams object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewIndicatorPropertiesTimesliceMetricParams(index string, timestampField string, metric IndicatorPropertiesTimesliceMetricParamsMetric) *IndicatorPropertiesTimesliceMetricParams { + this := IndicatorPropertiesTimesliceMetricParams{} + this.Index = index + this.TimestampField = timestampField + this.Metric = metric + return &this +} + +// NewIndicatorPropertiesTimesliceMetricParamsWithDefaults instantiates a new IndicatorPropertiesTimesliceMetricParams object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewIndicatorPropertiesTimesliceMetricParamsWithDefaults() *IndicatorPropertiesTimesliceMetricParams { + this := IndicatorPropertiesTimesliceMetricParams{} + return &this +} + +// GetIndex returns the Index field value +func (o *IndicatorPropertiesTimesliceMetricParams) GetIndex() string { + if o == nil { + var ret string + return ret + } + + return o.Index +} + +// GetIndexOk returns a tuple with the Index field value +// and a boolean to check if the value has been set. +func (o *IndicatorPropertiesTimesliceMetricParams) GetIndexOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Index, true +} + +// SetIndex sets field value +func (o *IndicatorPropertiesTimesliceMetricParams) SetIndex(v string) { + o.Index = v +} + +// GetFilter returns the Filter field value if set, zero value otherwise. +func (o *IndicatorPropertiesTimesliceMetricParams) GetFilter() string { + if o == nil || IsNil(o.Filter) { + var ret string + return ret + } + return *o.Filter +} + +// GetFilterOk returns a tuple with the Filter field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *IndicatorPropertiesTimesliceMetricParams) GetFilterOk() (*string, bool) { + if o == nil || IsNil(o.Filter) { + return nil, false + } + return o.Filter, true +} + +// HasFilter returns a boolean if a field has been set. +func (o *IndicatorPropertiesTimesliceMetricParams) HasFilter() bool { + if o != nil && !IsNil(o.Filter) { + return true + } + + return false +} + +// SetFilter gets a reference to the given string and assigns it to the Filter field. +func (o *IndicatorPropertiesTimesliceMetricParams) SetFilter(v string) { + o.Filter = &v +} + +// GetTimestampField returns the TimestampField field value +func (o *IndicatorPropertiesTimesliceMetricParams) GetTimestampField() string { + if o == nil { + var ret string + return ret + } + + return o.TimestampField +} + +// GetTimestampFieldOk returns a tuple with the TimestampField field value +// and a boolean to check if the value has been set. +func (o *IndicatorPropertiesTimesliceMetricParams) GetTimestampFieldOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.TimestampField, true +} + +// SetTimestampField sets field value +func (o *IndicatorPropertiesTimesliceMetricParams) SetTimestampField(v string) { + o.TimestampField = v +} + +// GetMetric returns the Metric field value +func (o *IndicatorPropertiesTimesliceMetricParams) GetMetric() IndicatorPropertiesTimesliceMetricParamsMetric { + if o == nil { + var ret IndicatorPropertiesTimesliceMetricParamsMetric + return ret + } + + return o.Metric +} + +// GetMetricOk returns a tuple with the Metric field value +// and a boolean to check if the value has been set. +func (o *IndicatorPropertiesTimesliceMetricParams) GetMetricOk() (*IndicatorPropertiesTimesliceMetricParamsMetric, bool) { + if o == nil { + return nil, false + } + return &o.Metric, true +} + +// SetMetric sets field value +func (o *IndicatorPropertiesTimesliceMetricParams) SetMetric(v IndicatorPropertiesTimesliceMetricParamsMetric) { + o.Metric = v +} + +func (o IndicatorPropertiesTimesliceMetricParams) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o IndicatorPropertiesTimesliceMetricParams) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["index"] = o.Index + if !IsNil(o.Filter) { + toSerialize["filter"] = o.Filter + } + toSerialize["timestampField"] = o.TimestampField + toSerialize["metric"] = o.Metric + return toSerialize, nil +} + +type NullableIndicatorPropertiesTimesliceMetricParams struct { + value *IndicatorPropertiesTimesliceMetricParams + isSet bool +} + +func (v NullableIndicatorPropertiesTimesliceMetricParams) Get() *IndicatorPropertiesTimesliceMetricParams { + return v.value +} + +func (v *NullableIndicatorPropertiesTimesliceMetricParams) Set(val *IndicatorPropertiesTimesliceMetricParams) { + v.value = val + v.isSet = true +} + +func (v NullableIndicatorPropertiesTimesliceMetricParams) IsSet() bool { + return v.isSet +} + +func (v *NullableIndicatorPropertiesTimesliceMetricParams) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableIndicatorPropertiesTimesliceMetricParams(val *IndicatorPropertiesTimesliceMetricParams) *NullableIndicatorPropertiesTimesliceMetricParams { + return &NullableIndicatorPropertiesTimesliceMetricParams{value: val, isSet: true} +} + +func (v NullableIndicatorPropertiesTimesliceMetricParams) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableIndicatorPropertiesTimesliceMetricParams) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/generated/slo/model_indicator_properties_timeslice_metric_params_metric.go b/generated/slo/model_indicator_properties_timeslice_metric_params_metric.go new file mode 100644 index 000000000..89435056d --- /dev/null +++ b/generated/slo/model_indicator_properties_timeslice_metric_params_metric.go @@ -0,0 +1,200 @@ +/* +SLOs + +OpenAPI schema for SLOs endpoints + +API version: 1.0 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package slo + +import ( + "encoding/json" +) + +// checks if the IndicatorPropertiesTimesliceMetricParamsMetric type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &IndicatorPropertiesTimesliceMetricParamsMetric{} + +// IndicatorPropertiesTimesliceMetricParamsMetric An object defining the metrics, equation, and threshold to determine if it's a good slice or not +type IndicatorPropertiesTimesliceMetricParamsMetric struct { + // List of metrics with their name, aggregation type, and field. + Metrics []IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner `json:"metrics"` + // The equation to calculate the metric. + Equation string `json:"equation"` + // The comparator to use to compare the equation to the threshold. + Comparator string `json:"comparator"` + // The threshold used to determine if the metric is a good slice or not. + Threshold float64 `json:"threshold"` +} + +// NewIndicatorPropertiesTimesliceMetricParamsMetric instantiates a new IndicatorPropertiesTimesliceMetricParamsMetric object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewIndicatorPropertiesTimesliceMetricParamsMetric(metrics []IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner, equation string, comparator string, threshold float64) *IndicatorPropertiesTimesliceMetricParamsMetric { + this := IndicatorPropertiesTimesliceMetricParamsMetric{} + this.Metrics = metrics + this.Equation = equation + this.Comparator = comparator + this.Threshold = threshold + return &this +} + +// NewIndicatorPropertiesTimesliceMetricParamsMetricWithDefaults instantiates a new IndicatorPropertiesTimesliceMetricParamsMetric object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewIndicatorPropertiesTimesliceMetricParamsMetricWithDefaults() *IndicatorPropertiesTimesliceMetricParamsMetric { + this := IndicatorPropertiesTimesliceMetricParamsMetric{} + return &this +} + +// GetMetrics returns the Metrics field value +func (o *IndicatorPropertiesTimesliceMetricParamsMetric) GetMetrics() []IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner { + if o == nil { + var ret []IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner + return ret + } + + return o.Metrics +} + +// GetMetricsOk returns a tuple with the Metrics field value +// and a boolean to check if the value has been set. +func (o *IndicatorPropertiesTimesliceMetricParamsMetric) GetMetricsOk() ([]IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner, bool) { + if o == nil { + return nil, false + } + return o.Metrics, true +} + +// SetMetrics sets field value +func (o *IndicatorPropertiesTimesliceMetricParamsMetric) SetMetrics(v []IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) { + o.Metrics = v +} + +// GetEquation returns the Equation field value +func (o *IndicatorPropertiesTimesliceMetricParamsMetric) GetEquation() string { + if o == nil { + var ret string + return ret + } + + return o.Equation +} + +// GetEquationOk returns a tuple with the Equation field value +// and a boolean to check if the value has been set. +func (o *IndicatorPropertiesTimesliceMetricParamsMetric) GetEquationOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Equation, true +} + +// SetEquation sets field value +func (o *IndicatorPropertiesTimesliceMetricParamsMetric) SetEquation(v string) { + o.Equation = v +} + +// GetComparator returns the Comparator field value +func (o *IndicatorPropertiesTimesliceMetricParamsMetric) GetComparator() string { + if o == nil { + var ret string + return ret + } + + return o.Comparator +} + +// GetComparatorOk returns a tuple with the Comparator field value +// and a boolean to check if the value has been set. +func (o *IndicatorPropertiesTimesliceMetricParamsMetric) GetComparatorOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Comparator, true +} + +// SetComparator sets field value +func (o *IndicatorPropertiesTimesliceMetricParamsMetric) SetComparator(v string) { + o.Comparator = v +} + +// GetThreshold returns the Threshold field value +func (o *IndicatorPropertiesTimesliceMetricParamsMetric) GetThreshold() float64 { + if o == nil { + var ret float64 + return ret + } + + return o.Threshold +} + +// GetThresholdOk returns a tuple with the Threshold field value +// and a boolean to check if the value has been set. +func (o *IndicatorPropertiesTimesliceMetricParamsMetric) GetThresholdOk() (*float64, bool) { + if o == nil { + return nil, false + } + return &o.Threshold, true +} + +// SetThreshold sets field value +func (o *IndicatorPropertiesTimesliceMetricParamsMetric) SetThreshold(v float64) { + o.Threshold = v +} + +func (o IndicatorPropertiesTimesliceMetricParamsMetric) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o IndicatorPropertiesTimesliceMetricParamsMetric) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["metrics"] = o.Metrics + toSerialize["equation"] = o.Equation + toSerialize["comparator"] = o.Comparator + toSerialize["threshold"] = o.Threshold + return toSerialize, nil +} + +type NullableIndicatorPropertiesTimesliceMetricParamsMetric struct { + value *IndicatorPropertiesTimesliceMetricParamsMetric + isSet bool +} + +func (v NullableIndicatorPropertiesTimesliceMetricParamsMetric) Get() *IndicatorPropertiesTimesliceMetricParamsMetric { + return v.value +} + +func (v *NullableIndicatorPropertiesTimesliceMetricParamsMetric) Set(val *IndicatorPropertiesTimesliceMetricParamsMetric) { + v.value = val + v.isSet = true +} + +func (v NullableIndicatorPropertiesTimesliceMetricParamsMetric) IsSet() bool { + return v.isSet +} + +func (v *NullableIndicatorPropertiesTimesliceMetricParamsMetric) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableIndicatorPropertiesTimesliceMetricParamsMetric(val *IndicatorPropertiesTimesliceMetricParamsMetric) *NullableIndicatorPropertiesTimesliceMetricParamsMetric { + return &NullableIndicatorPropertiesTimesliceMetricParamsMetric{value: val, isSet: true} +} + +func (v NullableIndicatorPropertiesTimesliceMetricParamsMetric) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableIndicatorPropertiesTimesliceMetricParamsMetric) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/generated/slo/model_indicator_properties_timeslice_metric_params_metric_metrics_inner.go b/generated/slo/model_indicator_properties_timeslice_metric_params_metric_metrics_inner.go new file mode 100644 index 000000000..828f796ee --- /dev/null +++ b/generated/slo/model_indicator_properties_timeslice_metric_params_metric_metrics_inner.go @@ -0,0 +1,121 @@ +/* +SLOs + +OpenAPI schema for SLOs endpoints + +API version: 1.0 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package slo + +import ( + "encoding/json" + "fmt" +) + +// IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner struct for IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner +type IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner struct { + TimesliceMetricBasicMetricWithField *TimesliceMetricBasicMetricWithField + TimesliceMetricDocCountMetric *TimesliceMetricDocCountMetric + TimesliceMetricPercentileMetric *TimesliceMetricPercentileMetric +} + +// Unmarshal JSON data into any of the pointers in the struct +func (dst *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) UnmarshalJSON(data []byte) error { + var err error + // try to unmarshal JSON data into TimesliceMetricBasicMetricWithField + err = json.Unmarshal(data, &dst.TimesliceMetricBasicMetricWithField) + if err == nil { + jsonTimesliceMetricBasicMetricWithField, _ := json.Marshal(dst.TimesliceMetricBasicMetricWithField) + if string(jsonTimesliceMetricBasicMetricWithField) == "{}" { // empty struct + dst.TimesliceMetricBasicMetricWithField = nil + } else { + return nil // data stored in dst.TimesliceMetricBasicMetricWithField, return on the first match + } + } else { + dst.TimesliceMetricBasicMetricWithField = nil + } + + // try to unmarshal JSON data into TimesliceMetricDocCountMetric + err = json.Unmarshal(data, &dst.TimesliceMetricDocCountMetric) + if err == nil { + jsonTimesliceMetricDocCountMetric, _ := json.Marshal(dst.TimesliceMetricDocCountMetric) + if string(jsonTimesliceMetricDocCountMetric) == "{}" { // empty struct + dst.TimesliceMetricDocCountMetric = nil + } else { + return nil // data stored in dst.TimesliceMetricDocCountMetric, return on the first match + } + } else { + dst.TimesliceMetricDocCountMetric = nil + } + + // try to unmarshal JSON data into TimesliceMetricPercentileMetric + err = json.Unmarshal(data, &dst.TimesliceMetricPercentileMetric) + if err == nil { + jsonTimesliceMetricPercentileMetric, _ := json.Marshal(dst.TimesliceMetricPercentileMetric) + if string(jsonTimesliceMetricPercentileMetric) == "{}" { // empty struct + dst.TimesliceMetricPercentileMetric = nil + } else { + return nil // data stored in dst.TimesliceMetricPercentileMetric, return on the first match + } + } else { + dst.TimesliceMetricPercentileMetric = nil + } + + return fmt.Errorf("data failed to match schemas in anyOf(IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner)") +} + +// Marshal data from the first non-nil pointers in the struct to JSON +func (src *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) MarshalJSON() ([]byte, error) { + if src.TimesliceMetricBasicMetricWithField != nil { + return json.Marshal(&src.TimesliceMetricBasicMetricWithField) + } + + if src.TimesliceMetricDocCountMetric != nil { + return json.Marshal(&src.TimesliceMetricDocCountMetric) + } + + if src.TimesliceMetricPercentileMetric != nil { + return json.Marshal(&src.TimesliceMetricPercentileMetric) + } + + return nil, nil // no data in anyOf schemas +} + +type NullableIndicatorPropertiesTimesliceMetricParamsMetricMetricsInner struct { + value *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner + isSet bool +} + +func (v NullableIndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) Get() *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner { + return v.value +} + +func (v *NullableIndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) Set(val *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) { + v.value = val + v.isSet = true +} + +func (v NullableIndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) IsSet() bool { + return v.isSet +} + +func (v *NullableIndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableIndicatorPropertiesTimesliceMetricParamsMetricMetricsInner(val *IndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) *NullableIndicatorPropertiesTimesliceMetricParamsMetricMetricsInner { + return &NullableIndicatorPropertiesTimesliceMetricParamsMetricMetricsInner{value: val, isSet: true} +} + +func (v NullableIndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableIndicatorPropertiesTimesliceMetricParamsMetricMetricsInner) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/generated/slo/model_slo_response.go b/generated/slo/model_slo_response.go index be4584751..91044e65b 100644 --- a/generated/slo/model_slo_response.go +++ b/generated/slo/model_slo_response.go @@ -39,6 +39,8 @@ type SloResponse struct { GroupBy string `json:"groupBy"` // the value derived from the groupBy field, if present, otherwise '*' InstanceId string `json:"instanceId"` + // List of tags + Tags []string `json:"tags"` // The creation date CreatedAt string `json:"createdAt"` // The last update date @@ -49,7 +51,7 @@ type SloResponse struct { // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewSloResponse(id string, name string, description string, indicator SloResponseIndicator, timeWindow TimeWindow, budgetingMethod BudgetingMethod, objective Objective, settings Settings, revision float64, summary Summary, enabled bool, groupBy string, instanceId string, createdAt string, updatedAt string) *SloResponse { +func NewSloResponse(id string, name string, description string, indicator SloResponseIndicator, timeWindow TimeWindow, budgetingMethod BudgetingMethod, objective Objective, settings Settings, revision float64, summary Summary, enabled bool, groupBy string, instanceId string, tags []string, createdAt string, updatedAt string) *SloResponse { this := SloResponse{} this.Id = id this.Name = name @@ -64,6 +66,7 @@ func NewSloResponse(id string, name string, description string, indicator SloRes this.Enabled = enabled this.GroupBy = groupBy this.InstanceId = instanceId + this.Tags = tags this.CreatedAt = createdAt this.UpdatedAt = updatedAt return &this @@ -389,6 +392,30 @@ func (o *SloResponse) SetInstanceId(v string) { o.InstanceId = v } +// GetTags returns the Tags field value +func (o *SloResponse) GetTags() []string { + if o == nil { + var ret []string + return ret + } + + return o.Tags +} + +// GetTagsOk returns a tuple with the Tags field value +// and a boolean to check if the value has been set. +func (o *SloResponse) GetTagsOk() ([]string, bool) { + if o == nil { + return nil, false + } + return o.Tags, true +} + +// SetTags sets field value +func (o *SloResponse) SetTags(v []string) { + o.Tags = v +} + // GetCreatedAt returns the CreatedAt field value func (o *SloResponse) GetCreatedAt() string { if o == nil { @@ -460,6 +487,7 @@ func (o SloResponse) ToMap() (map[string]interface{}, error) { toSerialize["enabled"] = o.Enabled toSerialize["groupBy"] = o.GroupBy toSerialize["instanceId"] = o.InstanceId + toSerialize["tags"] = o.Tags toSerialize["createdAt"] = o.CreatedAt toSerialize["updatedAt"] = o.UpdatedAt return toSerialize, nil diff --git a/generated/slo/model_slo_response_indicator.go b/generated/slo/model_slo_response_indicator.go index 171d83a6a..e0147a4dd 100644 --- a/generated/slo/model_slo_response_indicator.go +++ b/generated/slo/model_slo_response_indicator.go @@ -22,6 +22,7 @@ type SloResponseIndicator struct { IndicatorPropertiesCustomKql *IndicatorPropertiesCustomKql IndicatorPropertiesCustomMetric *IndicatorPropertiesCustomMetric IndicatorPropertiesHistogram *IndicatorPropertiesHistogram + IndicatorPropertiesTimesliceMetric *IndicatorPropertiesTimesliceMetric } // IndicatorPropertiesApmAvailabilityAsSloResponseIndicator is a convenience function that returns IndicatorPropertiesApmAvailability wrapped in SloResponseIndicator @@ -59,6 +60,13 @@ func IndicatorPropertiesHistogramAsSloResponseIndicator(v *IndicatorPropertiesHi } } +// IndicatorPropertiesTimesliceMetricAsSloResponseIndicator is a convenience function that returns IndicatorPropertiesTimesliceMetric wrapped in SloResponseIndicator +func IndicatorPropertiesTimesliceMetricAsSloResponseIndicator(v *IndicatorPropertiesTimesliceMetric) SloResponseIndicator { + return SloResponseIndicator{ + IndicatorPropertiesTimesliceMetric: v, + } +} + // Unmarshal JSON data into one of the pointers in the struct func (dst *SloResponseIndicator) UnmarshalJSON(data []byte) error { var err error @@ -129,6 +137,18 @@ func (dst *SloResponseIndicator) UnmarshalJSON(data []byte) error { } } + // check if the discriminator value is 'indicator_properties_timeslice_metric' + if jsonDict["type"] == "indicator_properties_timeslice_metric" { + // try to unmarshal JSON data into IndicatorPropertiesTimesliceMetric + err = json.Unmarshal(data, &dst.IndicatorPropertiesTimesliceMetric) + if err == nil { + return nil // data stored in dst.IndicatorPropertiesTimesliceMetric, return on the first match + } else { + dst.IndicatorPropertiesTimesliceMetric = nil + return fmt.Errorf("failed to unmarshal SloResponseIndicator as IndicatorPropertiesTimesliceMetric: %s", err.Error()) + } + } + // check if the discriminator value is 'sli.apm.transactionDuration' if jsonDict["type"] == "sli.apm.transactionDuration" { // try to unmarshal JSON data into IndicatorPropertiesApmLatency @@ -189,6 +209,18 @@ func (dst *SloResponseIndicator) UnmarshalJSON(data []byte) error { } } + // check if the discriminator value is 'sli.metric.timeslice' + if jsonDict["type"] == "sli.metric.timeslice" { + // try to unmarshal JSON data into IndicatorPropertiesTimesliceMetric + err = json.Unmarshal(data, &dst.IndicatorPropertiesTimesliceMetric) + if err == nil { + return nil // data stored in dst.IndicatorPropertiesTimesliceMetric, return on the first match + } else { + dst.IndicatorPropertiesTimesliceMetric = nil + return fmt.Errorf("failed to unmarshal SloResponseIndicator as IndicatorPropertiesTimesliceMetric: %s", err.Error()) + } + } + return nil } @@ -214,6 +246,10 @@ func (src SloResponseIndicator) MarshalJSON() ([]byte, error) { return json.Marshal(&src.IndicatorPropertiesHistogram) } + if src.IndicatorPropertiesTimesliceMetric != nil { + return json.Marshal(&src.IndicatorPropertiesTimesliceMetric) + } + return nil, nil // no data in oneOf schemas } @@ -242,6 +278,10 @@ func (obj *SloResponseIndicator) GetActualInstance() interface{} { return obj.IndicatorPropertiesHistogram } + if obj.IndicatorPropertiesTimesliceMetric != nil { + return obj.IndicatorPropertiesTimesliceMetric + } + // all schemas are nil return nil } diff --git a/generated/slo/model_timeslice_metric_basic_metric_with_field.go b/generated/slo/model_timeslice_metric_basic_metric_with_field.go new file mode 100644 index 000000000..6f3e23eda --- /dev/null +++ b/generated/slo/model_timeslice_metric_basic_metric_with_field.go @@ -0,0 +1,209 @@ +/* +SLOs + +OpenAPI schema for SLOs endpoints + +API version: 1.0 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package slo + +import ( + "encoding/json" +) + +// checks if the TimesliceMetricBasicMetricWithField type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &TimesliceMetricBasicMetricWithField{} + +// TimesliceMetricBasicMetricWithField struct for TimesliceMetricBasicMetricWithField +type TimesliceMetricBasicMetricWithField struct { + // The name of the metric. Only valid options are A-Z + Name string `json:"name"` + // The aggregation type of the metric. + Aggregation string `json:"aggregation"` + // The field of the metric. + Field string `json:"field"` + // The filter to apply to the metric. + Filter *string `json:"filter,omitempty"` +} + +// NewTimesliceMetricBasicMetricWithField instantiates a new TimesliceMetricBasicMetricWithField object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewTimesliceMetricBasicMetricWithField(name string, aggregation string, field string) *TimesliceMetricBasicMetricWithField { + this := TimesliceMetricBasicMetricWithField{} + this.Name = name + this.Aggregation = aggregation + this.Field = field + return &this +} + +// NewTimesliceMetricBasicMetricWithFieldWithDefaults instantiates a new TimesliceMetricBasicMetricWithField object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewTimesliceMetricBasicMetricWithFieldWithDefaults() *TimesliceMetricBasicMetricWithField { + this := TimesliceMetricBasicMetricWithField{} + return &this +} + +// GetName returns the Name field value +func (o *TimesliceMetricBasicMetricWithField) GetName() string { + if o == nil { + var ret string + return ret + } + + return o.Name +} + +// GetNameOk returns a tuple with the Name field value +// and a boolean to check if the value has been set. +func (o *TimesliceMetricBasicMetricWithField) GetNameOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Name, true +} + +// SetName sets field value +func (o *TimesliceMetricBasicMetricWithField) SetName(v string) { + o.Name = v +} + +// GetAggregation returns the Aggregation field value +func (o *TimesliceMetricBasicMetricWithField) GetAggregation() string { + if o == nil { + var ret string + return ret + } + + return o.Aggregation +} + +// GetAggregationOk returns a tuple with the Aggregation field value +// and a boolean to check if the value has been set. +func (o *TimesliceMetricBasicMetricWithField) GetAggregationOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Aggregation, true +} + +// SetAggregation sets field value +func (o *TimesliceMetricBasicMetricWithField) SetAggregation(v string) { + o.Aggregation = v +} + +// GetField returns the Field field value +func (o *TimesliceMetricBasicMetricWithField) GetField() string { + if o == nil { + var ret string + return ret + } + + return o.Field +} + +// GetFieldOk returns a tuple with the Field field value +// and a boolean to check if the value has been set. +func (o *TimesliceMetricBasicMetricWithField) GetFieldOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Field, true +} + +// SetField sets field value +func (o *TimesliceMetricBasicMetricWithField) SetField(v string) { + o.Field = v +} + +// GetFilter returns the Filter field value if set, zero value otherwise. +func (o *TimesliceMetricBasicMetricWithField) GetFilter() string { + if o == nil || IsNil(o.Filter) { + var ret string + return ret + } + return *o.Filter +} + +// GetFilterOk returns a tuple with the Filter field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *TimesliceMetricBasicMetricWithField) GetFilterOk() (*string, bool) { + if o == nil || IsNil(o.Filter) { + return nil, false + } + return o.Filter, true +} + +// HasFilter returns a boolean if a field has been set. +func (o *TimesliceMetricBasicMetricWithField) HasFilter() bool { + if o != nil && !IsNil(o.Filter) { + return true + } + + return false +} + +// SetFilter gets a reference to the given string and assigns it to the Filter field. +func (o *TimesliceMetricBasicMetricWithField) SetFilter(v string) { + o.Filter = &v +} + +func (o TimesliceMetricBasicMetricWithField) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o TimesliceMetricBasicMetricWithField) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["name"] = o.Name + toSerialize["aggregation"] = o.Aggregation + toSerialize["field"] = o.Field + if !IsNil(o.Filter) { + toSerialize["filter"] = o.Filter + } + return toSerialize, nil +} + +type NullableTimesliceMetricBasicMetricWithField struct { + value *TimesliceMetricBasicMetricWithField + isSet bool +} + +func (v NullableTimesliceMetricBasicMetricWithField) Get() *TimesliceMetricBasicMetricWithField { + return v.value +} + +func (v *NullableTimesliceMetricBasicMetricWithField) Set(val *TimesliceMetricBasicMetricWithField) { + v.value = val + v.isSet = true +} + +func (v NullableTimesliceMetricBasicMetricWithField) IsSet() bool { + return v.isSet +} + +func (v *NullableTimesliceMetricBasicMetricWithField) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableTimesliceMetricBasicMetricWithField(val *TimesliceMetricBasicMetricWithField) *NullableTimesliceMetricBasicMetricWithField { + return &NullableTimesliceMetricBasicMetricWithField{value: val, isSet: true} +} + +func (v NullableTimesliceMetricBasicMetricWithField) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableTimesliceMetricBasicMetricWithField) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/generated/slo/model_timeslice_metric_doc_count_metric.go b/generated/slo/model_timeslice_metric_doc_count_metric.go new file mode 100644 index 000000000..ac35571c3 --- /dev/null +++ b/generated/slo/model_timeslice_metric_doc_count_metric.go @@ -0,0 +1,181 @@ +/* +SLOs + +OpenAPI schema for SLOs endpoints + +API version: 1.0 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package slo + +import ( + "encoding/json" +) + +// checks if the TimesliceMetricDocCountMetric type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &TimesliceMetricDocCountMetric{} + +// TimesliceMetricDocCountMetric struct for TimesliceMetricDocCountMetric +type TimesliceMetricDocCountMetric struct { + // The name of the metric. Only valid options are A-Z + Name string `json:"name"` + // The aggregation type of the metric. Only valid option is \"doc_count\" + Aggregation string `json:"aggregation"` + // The filter to apply to the metric. + Filter *string `json:"filter,omitempty"` +} + +// NewTimesliceMetricDocCountMetric instantiates a new TimesliceMetricDocCountMetric object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewTimesliceMetricDocCountMetric(name string, aggregation string) *TimesliceMetricDocCountMetric { + this := TimesliceMetricDocCountMetric{} + this.Name = name + this.Aggregation = aggregation + return &this +} + +// NewTimesliceMetricDocCountMetricWithDefaults instantiates a new TimesliceMetricDocCountMetric object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewTimesliceMetricDocCountMetricWithDefaults() *TimesliceMetricDocCountMetric { + this := TimesliceMetricDocCountMetric{} + return &this +} + +// GetName returns the Name field value +func (o *TimesliceMetricDocCountMetric) GetName() string { + if o == nil { + var ret string + return ret + } + + return o.Name +} + +// GetNameOk returns a tuple with the Name field value +// and a boolean to check if the value has been set. +func (o *TimesliceMetricDocCountMetric) GetNameOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Name, true +} + +// SetName sets field value +func (o *TimesliceMetricDocCountMetric) SetName(v string) { + o.Name = v +} + +// GetAggregation returns the Aggregation field value +func (o *TimesliceMetricDocCountMetric) GetAggregation() string { + if o == nil { + var ret string + return ret + } + + return o.Aggregation +} + +// GetAggregationOk returns a tuple with the Aggregation field value +// and a boolean to check if the value has been set. +func (o *TimesliceMetricDocCountMetric) GetAggregationOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Aggregation, true +} + +// SetAggregation sets field value +func (o *TimesliceMetricDocCountMetric) SetAggregation(v string) { + o.Aggregation = v +} + +// GetFilter returns the Filter field value if set, zero value otherwise. +func (o *TimesliceMetricDocCountMetric) GetFilter() string { + if o == nil || IsNil(o.Filter) { + var ret string + return ret + } + return *o.Filter +} + +// GetFilterOk returns a tuple with the Filter field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *TimesliceMetricDocCountMetric) GetFilterOk() (*string, bool) { + if o == nil || IsNil(o.Filter) { + return nil, false + } + return o.Filter, true +} + +// HasFilter returns a boolean if a field has been set. +func (o *TimesliceMetricDocCountMetric) HasFilter() bool { + if o != nil && !IsNil(o.Filter) { + return true + } + + return false +} + +// SetFilter gets a reference to the given string and assigns it to the Filter field. +func (o *TimesliceMetricDocCountMetric) SetFilter(v string) { + o.Filter = &v +} + +func (o TimesliceMetricDocCountMetric) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o TimesliceMetricDocCountMetric) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["name"] = o.Name + toSerialize["aggregation"] = o.Aggregation + if !IsNil(o.Filter) { + toSerialize["filter"] = o.Filter + } + return toSerialize, nil +} + +type NullableTimesliceMetricDocCountMetric struct { + value *TimesliceMetricDocCountMetric + isSet bool +} + +func (v NullableTimesliceMetricDocCountMetric) Get() *TimesliceMetricDocCountMetric { + return v.value +} + +func (v *NullableTimesliceMetricDocCountMetric) Set(val *TimesliceMetricDocCountMetric) { + v.value = val + v.isSet = true +} + +func (v NullableTimesliceMetricDocCountMetric) IsSet() bool { + return v.isSet +} + +func (v *NullableTimesliceMetricDocCountMetric) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableTimesliceMetricDocCountMetric(val *TimesliceMetricDocCountMetric) *NullableTimesliceMetricDocCountMetric { + return &NullableTimesliceMetricDocCountMetric{value: val, isSet: true} +} + +func (v NullableTimesliceMetricDocCountMetric) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableTimesliceMetricDocCountMetric) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/generated/slo/model_timeslice_metric_percentile_metric.go b/generated/slo/model_timeslice_metric_percentile_metric.go new file mode 100644 index 000000000..ada902804 --- /dev/null +++ b/generated/slo/model_timeslice_metric_percentile_metric.go @@ -0,0 +1,237 @@ +/* +SLOs + +OpenAPI schema for SLOs endpoints + +API version: 1.0 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package slo + +import ( + "encoding/json" +) + +// checks if the TimesliceMetricPercentileMetric type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &TimesliceMetricPercentileMetric{} + +// TimesliceMetricPercentileMetric struct for TimesliceMetricPercentileMetric +type TimesliceMetricPercentileMetric struct { + // The name of the metric. Only valid options are A-Z + Name string `json:"name"` + // The aggregation type of the metric. Only valid option is \"percentile\" + Aggregation string `json:"aggregation"` + // The field of the metric. + Field string `json:"field"` + // The percentile value. + Percentile float64 `json:"percentile"` + // The filter to apply to the metric. + Filter *string `json:"filter,omitempty"` +} + +// NewTimesliceMetricPercentileMetric instantiates a new TimesliceMetricPercentileMetric object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewTimesliceMetricPercentileMetric(name string, aggregation string, field string, percentile float64) *TimesliceMetricPercentileMetric { + this := TimesliceMetricPercentileMetric{} + this.Name = name + this.Aggregation = aggregation + this.Field = field + this.Percentile = percentile + return &this +} + +// NewTimesliceMetricPercentileMetricWithDefaults instantiates a new TimesliceMetricPercentileMetric object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewTimesliceMetricPercentileMetricWithDefaults() *TimesliceMetricPercentileMetric { + this := TimesliceMetricPercentileMetric{} + return &this +} + +// GetName returns the Name field value +func (o *TimesliceMetricPercentileMetric) GetName() string { + if o == nil { + var ret string + return ret + } + + return o.Name +} + +// GetNameOk returns a tuple with the Name field value +// and a boolean to check if the value has been set. +func (o *TimesliceMetricPercentileMetric) GetNameOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Name, true +} + +// SetName sets field value +func (o *TimesliceMetricPercentileMetric) SetName(v string) { + o.Name = v +} + +// GetAggregation returns the Aggregation field value +func (o *TimesliceMetricPercentileMetric) GetAggregation() string { + if o == nil { + var ret string + return ret + } + + return o.Aggregation +} + +// GetAggregationOk returns a tuple with the Aggregation field value +// and a boolean to check if the value has been set. +func (o *TimesliceMetricPercentileMetric) GetAggregationOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Aggregation, true +} + +// SetAggregation sets field value +func (o *TimesliceMetricPercentileMetric) SetAggregation(v string) { + o.Aggregation = v +} + +// GetField returns the Field field value +func (o *TimesliceMetricPercentileMetric) GetField() string { + if o == nil { + var ret string + return ret + } + + return o.Field +} + +// GetFieldOk returns a tuple with the Field field value +// and a boolean to check if the value has been set. +func (o *TimesliceMetricPercentileMetric) GetFieldOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Field, true +} + +// SetField sets field value +func (o *TimesliceMetricPercentileMetric) SetField(v string) { + o.Field = v +} + +// GetPercentile returns the Percentile field value +func (o *TimesliceMetricPercentileMetric) GetPercentile() float64 { + if o == nil { + var ret float64 + return ret + } + + return o.Percentile +} + +// GetPercentileOk returns a tuple with the Percentile field value +// and a boolean to check if the value has been set. +func (o *TimesliceMetricPercentileMetric) GetPercentileOk() (*float64, bool) { + if o == nil { + return nil, false + } + return &o.Percentile, true +} + +// SetPercentile sets field value +func (o *TimesliceMetricPercentileMetric) SetPercentile(v float64) { + o.Percentile = v +} + +// GetFilter returns the Filter field value if set, zero value otherwise. +func (o *TimesliceMetricPercentileMetric) GetFilter() string { + if o == nil || IsNil(o.Filter) { + var ret string + return ret + } + return *o.Filter +} + +// GetFilterOk returns a tuple with the Filter field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *TimesliceMetricPercentileMetric) GetFilterOk() (*string, bool) { + if o == nil || IsNil(o.Filter) { + return nil, false + } + return o.Filter, true +} + +// HasFilter returns a boolean if a field has been set. +func (o *TimesliceMetricPercentileMetric) HasFilter() bool { + if o != nil && !IsNil(o.Filter) { + return true + } + + return false +} + +// SetFilter gets a reference to the given string and assigns it to the Filter field. +func (o *TimesliceMetricPercentileMetric) SetFilter(v string) { + o.Filter = &v +} + +func (o TimesliceMetricPercentileMetric) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o TimesliceMetricPercentileMetric) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["name"] = o.Name + toSerialize["aggregation"] = o.Aggregation + toSerialize["field"] = o.Field + toSerialize["percentile"] = o.Percentile + if !IsNil(o.Filter) { + toSerialize["filter"] = o.Filter + } + return toSerialize, nil +} + +type NullableTimesliceMetricPercentileMetric struct { + value *TimesliceMetricPercentileMetric + isSet bool +} + +func (v NullableTimesliceMetricPercentileMetric) Get() *TimesliceMetricPercentileMetric { + return v.value +} + +func (v *NullableTimesliceMetricPercentileMetric) Set(val *TimesliceMetricPercentileMetric) { + v.value = val + v.isSet = true +} + +func (v NullableTimesliceMetricPercentileMetric) IsSet() bool { + return v.isSet +} + +func (v *NullableTimesliceMetricPercentileMetric) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableTimesliceMetricPercentileMetric(val *TimesliceMetricPercentileMetric) *NullableTimesliceMetricPercentileMetric { + return &NullableTimesliceMetricPercentileMetric{value: val, isSet: true} +} + +func (v NullableTimesliceMetricPercentileMetric) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableTimesliceMetricPercentileMetric) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/generated/slo/model_update_slo_request.go b/generated/slo/model_update_slo_request.go index 45dd68c36..eb975d0a6 100644 --- a/generated/slo/model_update_slo_request.go +++ b/generated/slo/model_update_slo_request.go @@ -28,6 +28,8 @@ type UpdateSloRequest struct { BudgetingMethod *BudgetingMethod `json:"budgetingMethod,omitempty"` Objective *Objective `json:"objective,omitempty"` Settings *Settings `json:"settings,omitempty"` + // List of tags + Tags []string `json:"tags,omitempty"` } // NewUpdateSloRequest instantiates a new UpdateSloRequest object @@ -271,6 +273,38 @@ func (o *UpdateSloRequest) SetSettings(v Settings) { o.Settings = &v } +// GetTags returns the Tags field value if set, zero value otherwise. +func (o *UpdateSloRequest) GetTags() []string { + if o == nil || IsNil(o.Tags) { + var ret []string + return ret + } + return o.Tags +} + +// GetTagsOk returns a tuple with the Tags field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateSloRequest) GetTagsOk() ([]string, bool) { + if o == nil || IsNil(o.Tags) { + return nil, false + } + return o.Tags, true +} + +// HasTags returns a boolean if a field has been set. +func (o *UpdateSloRequest) HasTags() bool { + if o != nil && !IsNil(o.Tags) { + return true + } + + return false +} + +// SetTags gets a reference to the given []string and assigns it to the Tags field. +func (o *UpdateSloRequest) SetTags(v []string) { + o.Tags = v +} + func (o UpdateSloRequest) MarshalJSON() ([]byte, error) { toSerialize, err := o.ToMap() if err != nil { @@ -302,6 +336,9 @@ func (o UpdateSloRequest) ToMap() (map[string]interface{}, error) { if !IsNil(o.Settings) { toSerialize["settings"] = o.Settings } + if !IsNil(o.Tags) { + toSerialize["tags"] = o.Tags + } return toSerialize, nil } diff --git a/internal/clients/kibana/slo.go b/internal/clients/kibana/slo.go index d09c4da40..518513745 100644 --- a/internal/clients/kibana/slo.go +++ b/internal/clients/kibana/slo.go @@ -72,6 +72,7 @@ func UpdateSlo(ctx context.Context, apiClient *clients.ApiClient, s models.Slo) BudgetingMethod: (*slo.BudgetingMethod)(&s.BudgetingMethod), Objective: &s.Objective, Settings: s.Settings, + Tags: s.Tags, } req := client.UpdateSloOp(ctxWithAuth, s.SpaceID, s.ID).KbnXsrf("true").UpdateSloRequest(reqModel) @@ -108,6 +109,8 @@ func CreateSlo(ctx context.Context, apiClient *clients.ApiClient, s models.Slo) BudgetingMethod: slo.BudgetingMethod(s.BudgetingMethod), Objective: s.Objective, Settings: s.Settings, + GroupBy: s.GroupBy, + Tags: s.Tags, } req := client.CreateSloOp(ctxWithAuth, s.SpaceID).KbnXsrf("true").CreateSloRequest(reqModel) sloRes, res, err := req.Execute() @@ -168,5 +171,6 @@ func sloResponseToModel(spaceID string, res *slo.SloResponse) *models.Slo { TimeWindow: res.TimeWindow, Objective: res.Objective, Settings: &res.Settings, + Tags: res.Tags, } } diff --git a/internal/clients/kibana/slo_test.go b/internal/clients/kibana/slo_test.go index 7f72deb57..5076acb8e 100644 --- a/internal/clients/kibana/slo_test.go +++ b/internal/clients/kibana/slo_test.go @@ -78,6 +78,69 @@ func Test_sloResponseToModel(t *testing.T) { }, }, + { + name: "should return tags if available", + spaceId: "space-id", + sloResponse: &slo.SloResponse{ + Id: "slo-id", + Name: "slo-name", + Description: "slo-description", + Indicator: slo.SloResponseIndicator{ + IndicatorPropertiesApmAvailability: &slo.IndicatorPropertiesApmAvailability{ + Type: "sli.apm.transactionErrorRate", + Params: slo.IndicatorPropertiesApmAvailabilityParams{ + Service: "slo-service", + Environment: "slo-environment", + TransactionType: "slo-transaction-type", + TransactionName: "slo-transaction-name", + Index: "slo-index", + }, + }, + }, + TimeWindow: slo.TimeWindow{ + Duration: "7d", + Type: "rolling", + }, + BudgetingMethod: "occurrences", + Settings: slo.Settings{ + SyncDelay: &syncDelay, + }, + Tags: []string{"tag-1", "another_tag"}, + Revision: 5.0, + Enabled: true, + CreatedAt: "2023-08-11T00:05:36.567Z", + UpdatedAt: "2023-08-11T00:05:36.567Z", + }, + expectedModel: &models.Slo{ + ID: "slo-id", + Name: "slo-name", + Description: "slo-description", + Indicator: slo.SloResponseIndicator{ + IndicatorPropertiesApmAvailability: &slo.IndicatorPropertiesApmAvailability{ + Type: "sli.apm.transactionErrorRate", + Params: slo.IndicatorPropertiesApmAvailabilityParams{ + Service: "slo-service", + Environment: "slo-environment", + TransactionType: "slo-transaction-type", + TransactionName: "slo-transaction-name", + Index: "slo-index", + }, + }, + }, + TimeWindow: slo.TimeWindow{ + Duration: "7d", + Type: "rolling", + }, + BudgetingMethod: "occurrences", + Settings: &slo.Settings{ + SyncDelay: &syncDelay, + }, + SpaceID: "space-id", + Tags: []string{"tag-1", "another_tag"}, + GroupBy: nil, + }, + }, + { name: "nil response should return a nil model", spaceId: "space-id", diff --git a/internal/kibana/slo.go b/internal/kibana/slo.go index bbb1eea3d..47ecae535 100644 --- a/internal/kibana/slo.go +++ b/internal/kibana/slo.go @@ -413,6 +413,15 @@ func ResourceSlo() *schema.Resource { Optional: true, ForceNew: false, }, + "tags": { + Description: "The tags for the SLO.", + Type: schema.TypeList, + Optional: true, + ForceNew: false, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, } return &schema.Resource{ @@ -467,8 +476,8 @@ func getSloFromResourceData(d *schema.ResourceData) (models.Slo, diag.Diagnostic Params: slo.IndicatorPropertiesCustomKqlParams{ Index: d.Get(indicatorType + ".0.index").(string), Filter: getOrNilString(indicatorType+".0.filter", d), - Good: getOrNilString(indicatorType+".0.good", d), - Total: getOrNilString(indicatorType+".0.total", d), + Good: d.Get(indicatorType + ".0.good").(string), + Total: d.Get(indicatorType + ".0.total").(string), TimestampField: d.Get(indicatorType + ".0.timestamp_field").(string), }, }, @@ -536,7 +545,7 @@ func getSloFromResourceData(d *schema.ResourceData) (models.Slo, diag.Diagnostic IndicatorPropertiesCustomMetric: &slo.IndicatorPropertiesCustomMetric{ Type: indicatorAddressToType[indicatorType], Params: slo.IndicatorPropertiesCustomMetricParams{ - Filter: d.Get(indicatorType + ".0.filter").(string), + Filter: getOrNilString(indicatorType+".0.filter", d), Index: d.Get(indicatorType + ".0.index").(string), TimestampField: d.Get(indicatorType + ".0.timestamp_field").(string), Total: slo.IndicatorPropertiesCustomMetricParamsTotal{ @@ -599,6 +608,12 @@ func getSloFromResourceData(d *schema.ResourceData) (models.Slo, diag.Diagnostic GroupBy: getOrNilString("group_by", d), } + if tags, ok := d.GetOk("tags"); ok { + for _, t := range tags.([]interface{}) { + slo.Tags = append(slo.Tags, t.(string)) + } + } + return slo, diags } @@ -827,6 +842,9 @@ func resourceSloRead(ctx context.Context, d *schema.ResourceData, meta interface if err := d.Set("budgeting_method", s.BudgetingMethod); err != nil { return diag.FromErr(err) } + if err := d.Set("tags", s.Tags); err != nil { + return diag.FromErr(err) + } return diags } diff --git a/internal/kibana/slo_test.go b/internal/kibana/slo_test.go index ce2187fa3..d32490244 100644 --- a/internal/kibana/slo_test.go +++ b/internal/kibana/slo_test.go @@ -2,6 +2,7 @@ package kibana_test import ( "context" + "encoding/json" "fmt" "regexp" "strings" @@ -28,7 +29,7 @@ func TestAccResourceSlo(t *testing.T) { Steps: []resource.TestStep{ { SkipFunc: versionutils.CheckIfVersionIsUnsupported(version.Must(version.NewSemver("8.9.0"))), - Config: getSLOConfig(sloName, "apm_latency_indicator", false), + Config: getSLOConfig(sloName, "apm_latency_indicator", false, []string{}, ""), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "name", sloName), resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "description", "fully sick SLO"), @@ -47,19 +48,18 @@ func TestAccResourceSlo(t *testing.T) { resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "settings.0.sync_delay", "1m"), resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "settings.0.frequency", "1m"), resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "space_id", "default"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "group_by", "some.field"), ), }, { //check that name can be updated SkipFunc: versionutils.CheckIfVersionIsUnsupported(version.Must(version.NewSemver("8.9.0"))), - Config: getSLOConfig(fmt.Sprintf("Updated %s", sloName), "apm_latency_indicator", false), + Config: getSLOConfig(fmt.Sprintf("Updated %s", sloName), "apm_latency_indicator", false, []string{}, ""), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "name", fmt.Sprintf("Updated %s", sloName)), ), }, { //check that settings can be updated from api-computed defaults SkipFunc: versionutils.CheckIfVersionIsUnsupported(version.Must(version.NewSemver("8.9.0"))), - Config: getSLOConfig(sloName, "apm_latency_indicator", true), + Config: getSLOConfig(sloName, "apm_latency_indicator", true, []string{}, ""), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "settings.0.sync_delay", "5m"), resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "settings.0.frequency", "5m"), @@ -67,7 +67,7 @@ func TestAccResourceSlo(t *testing.T) { }, { SkipFunc: versionutils.CheckIfVersionIsUnsupported(version.Must(version.NewSemver("8.9.0"))), - Config: getSLOConfig(sloName, "apm_availability_indicator", true), + Config: getSLOConfig(sloName, "apm_availability_indicator", true, []string{}, ""), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_availability_indicator.0.environment", "production"), resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_availability_indicator.0.service", "my-service"), @@ -78,7 +78,7 @@ func TestAccResourceSlo(t *testing.T) { }, { SkipFunc: versionutils.CheckIfVersionIsUnsupported(version.Must(version.NewSemver("8.9.0"))), - Config: getSLOConfig(sloName, "kql_custom_indicator", true), + Config: getSLOConfig(sloName, "kql_custom_indicator", true, []string{}, ""), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "kql_custom_indicator.0.index", "my-index"), resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "kql_custom_indicator.0.good", "latency < 300"), @@ -89,7 +89,7 @@ func TestAccResourceSlo(t *testing.T) { }, { SkipFunc: versionutils.CheckIfVersionIsUnsupported(version.Must(version.NewSemver("8.10.0"))), - Config: getSLOConfig(sloName, "histogram_custom_indicator", true), + Config: getSLOConfig(sloName, "histogram_custom_indicator", true, []string{}, ""), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.index", "my-index"), resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.good.0.field", "test"), @@ -103,7 +103,7 @@ func TestAccResourceSlo(t *testing.T) { }, { SkipFunc: versionutils.CheckIfVersionIsUnsupported(version.Must(version.NewSemver("8.10.0"))), - Config: getSLOConfig(sloName, "metric_custom_indicator", true), + Config: getSLOConfig(sloName, "metric_custom_indicator", true, []string{}, "some.field"), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.index", "my-index"), resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.good.0.metrics.0.name", "A"), @@ -112,6 +112,15 @@ func TestAccResourceSlo(t *testing.T) { resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.total.0.metrics.0.name", "A"), resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.total.0.metrics.0.aggregation", "sum"), resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.total.0.metrics.0.field", "processor.accepted"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "group_by", "some.field"), + ), + }, + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(version.Must(version.NewSemver("8.10.0"))), + Config: getSLOConfig(sloName, "metric_custom_indicator", true, []string{"tag-1", "another_tag"}, ""), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "tags.0", "tag-1"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "tags.1", "another_tag"), ), }, }, @@ -174,7 +183,7 @@ func TestAccResourceSloErrors(t *testing.T) { }` - budgetingMethodFailConfig := getSLOConfig("budgetingMethodFail", "apm_latency_indicator", false) + budgetingMethodFailConfig := getSLOConfig("budgetingMethodFail", "apm_latency_indicator", false, []string{}, "") budgetingMethodFailConfig = strings.Replace(budgetingMethodFailConfig, "budgeting_method = \"timeslices\"", "budgeting_method = \"supdawg\"", -1) resource.Test(t, resource.TestCase{ @@ -188,7 +197,7 @@ func TestAccResourceSloErrors(t *testing.T) { }, { SkipFunc: versionutils.CheckIfVersionIsUnsupported(version.Must(version.NewSemver("8.10.0-SNAPSHOT"))), - Config: getSLOConfig("failwhale", "histogram_custom_indicator_agg_fail", false), + Config: getSLOConfig("failwhale", "histogram_custom_indicator_agg_fail", false, []string{}, ""), ExpectError: regexp.MustCompile(`expected histogram_custom_indicator.0.good.0.aggregation to be one of \["?value_count"? "?range"?\], got supdawg`), }, { @@ -226,7 +235,7 @@ func checkResourceSloDestroy(s *terraform.State) error { return nil } -func getSLOConfig(name string, indicatorType string, settingsEnabled bool) string { +func getSLOConfig(name string, indicatorType string, settingsEnabled bool, tags []string, group_by string) string { var settings string if settingsEnabled { settings = ` @@ -239,6 +248,21 @@ func getSLOConfig(name string, indicatorType string, settingsEnabled bool) strin settings = "" } + var tagsOption string + if len(tags) != 0 { + tagsJson, _ := json.Marshal(tags) + tagsOption = "tags = " + string(tagsJson) + } else { + tagsOption = "" + } + + var groupByOption string + if len(group_by) != 0 { + groupByOption = "group_by = \"" + group_by + "\"" + } else { + groupByOption = "" + } + configTemplate := ` provider "elasticstack" { elasticsearch {} @@ -271,10 +295,11 @@ func getSLOConfig(name string, indicatorType string, settingsEnabled bool) strin %s - group_by = "some.field" + %s depends_on = [elasticstack_elasticsearch_index.my_index] + %s } ` @@ -381,6 +406,6 @@ func getSLOConfig(name string, indicatorType string, settingsEnabled bool) strin return indicator } - config := fmt.Sprintf(configTemplate, name, getIndicator(indicatorType), settings) + config := fmt.Sprintf(configTemplate, name, getIndicator(indicatorType), settings, groupByOption, tagsOption) return config } diff --git a/internal/models/slo.go b/internal/models/slo.go index d1d830729..9bad1a0ff 100644 --- a/internal/models/slo.go +++ b/internal/models/slo.go @@ -15,4 +15,5 @@ type Slo struct { Settings *slo.Settings SpaceID string GroupBy *string + Tags []string } From 416ef2af5fc3a8fcabf46937517150f868ec7347 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 10:06:46 +0100 Subject: [PATCH 11/12] Bump google.golang.org/grpc from 1.57.0 to 1.57.1 in /tools (#455) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.57.0 to 1.57.1. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.57.0...v1.57.1) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Thibault Richard --- tools/go.mod | 2 +- tools/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/go.mod b/tools/go.mod index 591691cab..ee1c9e22b 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -394,7 +394,7 @@ require ( google.golang.org/genproto v0.0.0-20230731193218-e0aa005b6bdf // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230731193218-e0aa005b6bdf // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230731193218-e0aa005b6bdf // indirect - google.golang.org/grpc v1.57.0 // indirect + google.golang.org/grpc v1.57.1 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/tools/go.sum b/tools/go.sum index 11898a110..6295ad302 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -1692,8 +1692,8 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5 google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= -google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= +google.golang.org/grpc v1.57.1 h1:upNTNqv0ES+2ZOOqACwVtS3Il8M12/+Hz41RCPzAjQg= +google.golang.org/grpc v1.57.1/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= From 19e3b2ff7b849e2660bd12c2aa0b324814dea4ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 10:18:34 +0100 Subject: [PATCH 12/12] Bump google.golang.org/grpc from 1.57.0 to 1.57.1 (#456) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.57.0 to 1.57.1. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.57.0...v1.57.1) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Thibault Richard --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 3626e221b..a369342c0 100644 --- a/go.mod +++ b/go.mod @@ -69,7 +69,7 @@ require ( golang.org/x/text v0.13.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect - google.golang.org/grpc v1.57.0 // indirect + google.golang.org/grpc v1.57.1 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 29b9f3eae..3e98a8a41 100644 --- a/go.sum +++ b/go.sum @@ -238,8 +238,8 @@ google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6 google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= -google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= +google.golang.org/grpc v1.57.1 h1:upNTNqv0ES+2ZOOqACwVtS3Il8M12/+Hz41RCPzAjQg= +google.golang.org/grpc v1.57.1/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=