From 97b8f095498280d7fb9e5d7110546f31ddd73fce Mon Sep 17 00:00:00 2001 From: michaelkad <45772690+michaelkad@users.noreply.github.com> Date: Mon, 4 Dec 2023 22:23:11 -0600 Subject: [PATCH 01/14] Update go.mod (#4963) - Update go.mod: bluemix-go version --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index bffd2441f8..fe7c351529 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/IBM-Cloud/terraform-provider-ibm go 1.18 require ( - github.com/IBM-Cloud/bluemix-go v0.0.0-20231123082353-50e8cc9c6959 + github.com/IBM-Cloud/bluemix-go v0.0.0-20231204080125-462fa9e436bc github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20231106114255-c50117860a3c github.com/IBM-Cloud/power-go-client v1.5.4 github.com/IBM/apigateway-go-sdk v0.0.0-20210714141226-a5d5d49caaca diff --git a/go.sum b/go.sum index 4477787f09..77c54968b8 100644 --- a/go.sum +++ b/go.sum @@ -102,6 +102,8 @@ github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3 github.com/DataDog/zstd v1.4.4/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/IBM-Cloud/bluemix-go v0.0.0-20231123082353-50e8cc9c6959 h1:dvvI4ybsYx6M7fFGrg3HjlNnYxEBi9jJdSU0JhjJbG8= github.com/IBM-Cloud/bluemix-go v0.0.0-20231123082353-50e8cc9c6959/go.mod h1:jIGLnIfj+uBv2ALz3rVHzNbNwt0V/bEWNeJKECa8Q+k= +github.com/IBM-Cloud/bluemix-go v0.0.0-20231204080125-462fa9e436bc h1:AeooCa6UMWycgKJ9n0do9PEZaNlYZZHqspfwUzPvopc= +github.com/IBM-Cloud/bluemix-go v0.0.0-20231204080125-462fa9e436bc/go.mod h1:jIGLnIfj+uBv2ALz3rVHzNbNwt0V/bEWNeJKECa8Q+k= github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20231106114255-c50117860a3c h1:tRS4VuOG3lHNG+yrsh3vZZQDVNLuFJB0oZbTJp9YXds= github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20231106114255-c50117860a3c/go.mod h1:xUQL9SGAjoZFd4GNjrjjtEpjpkgU7RFXRyHesbKTjiY= github.com/IBM-Cloud/ibm-cloud-cli-sdk v0.5.3/go.mod h1:RiUvKuHKTBmBApDMUQzBL14pQUGKcx/IioKQPIcRQjs= From de7b248d0b0cbb7e5b4351e7bf0bcafd12dc3ef7 Mon Sep 17 00:00:00 2001 From: ismirlia <90468712+ismirlia@users.noreply.github.com> Date: Fri, 8 Dec 2023 03:31:21 -0600 Subject: [PATCH 02/14] Fix IBM i documentation bug (#4969) * Fix IBM i documentation bug On several documentation pages, it incorrectly implied that IBMi was the only usable OS for that resource/data source. * Update help URLs --- website/docs/d/pi_key.html.markdown | 2 +- website/docs/d/pi_network.html.markdown | 2 +- website/docs/r/pi_network.html.markdown | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/website/docs/d/pi_key.html.markdown b/website/docs/d/pi_key.html.markdown index fab30bd2c2..19b824e44c 100644 --- a/website/docs/d/pi_key.html.markdown +++ b/website/docs/d/pi_key.html.markdown @@ -8,7 +8,7 @@ description: |- --- # ibm_pi_key -Retrieve information about the SSH key that is used for your Power Systems Virtual Server instance. The SSH key is used to access the instance after it is created. For more information, about [configuring your IBM i virtual machine (VM)](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-configuring-ibmi). +Retrieve information about the SSH key that is used for your Power Systems Virtual Server instance. The SSH key is used to access the instance after it is created. For more information, about [configuring your IBM virtual machine (VM)](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-creating-ssh-key). ## Example usage diff --git a/website/docs/d/pi_network.html.markdown b/website/docs/d/pi_network.html.markdown index 153b53696d..eea249a557 100644 --- a/website/docs/d/pi_network.html.markdown +++ b/website/docs/d/pi_network.html.markdown @@ -8,7 +8,7 @@ description: |- --- # ibm_pi_network -Retrieve information about the network that your Power Systems Virtual Server instance is connected to. For more information, about power virtual server instance network, see [setting up an IBM i network install server](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-preparing-install-server). +Retrieve information about the network that your Power Systems Virtual Server instance is connected to. For more information, about power virtual server instance network, see [setting up an IBM network install server](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-configuring-subnet). ## Example usage diff --git a/website/docs/r/pi_network.html.markdown b/website/docs/r/pi_network.html.markdown index ba60fc993c..23da3c3de9 100644 --- a/website/docs/r/pi_network.html.markdown +++ b/website/docs/r/pi_network.html.markdown @@ -8,7 +8,7 @@ description: |- # ibm_pi_network -Create, update, or delete a network connection for your Power Systems Virtual Server instance. For more information, about power virtual server instance network, see [setting up an IBM i network install server](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-preparing-install-server). +Create, update, or delete a network connection for your Power Systems Virtual Server instance. For more information, about power virtual server instance network, see [setting up an IBM network install server](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-configuring-subnet). ## Example usage From 1bb8e0577ebba4c965e2deda0b997f0300168e3f Mon Sep 17 00:00:00 2001 From: Riccardo Angelilli Date: Fri, 8 Dec 2023 17:00:36 +0100 Subject: [PATCH 03/14] Regenerate Projects TF to fix generated doc and samples (#4961) * fix integration test * fix integration test * fix integration test * fix name * pr comments * pr comments * fix doc * fix doc * new version * new version * new version * new version * update code to the latest SDK level * fix integration tests * fix integration tests * fix integration tests * fix integration tests * address PR comment * typo * typo * terraform * terraform * terraform * terraform * terraform * terraform * terraform * terraform * terraform * terraform * add wait for create and delete * add wait for create and delete * . * fix integration tests * fix integration tests * fix integration tests * fix integration tests * fix integration tests * regenerate * new code generation * new generated code * point to latest sdk * point to latest sdk * adjust test cases and doc * adjust samples * update to latest node sdk * merge with master * Update project_instance.html.markdown Fixing formatting issues * Update project_event_notification.html.markdown * Update README.md * Update variables.tf * Update project_event_notification.html.markdown * new version * terraform * terraform * terraform * terraform * terraform * terraform * terraform * terraform * terraform * terraform * feat: projects graph fragment pattern * align with origin/master * update test cases * restore README.md and versions.tf to master branch * remove duplicated entries * feat: graph fragment pattern poc * feat: restore definition blocks * regenerate the terraform code based on latest YAML * regenerate the terraform code based on latest YAML * regenerate the terraform code based on latest YAML * update doc * update doc * fix test cases * commit generated code * commit fix * commit fix * test cases * test cases * test cases * test cases * updates * upgrade to latest go sdk * update generated doc * update generated code * updated secrets baseline * update code to latest API changes * secrets * fix secrets * update samples with real values * update secrets * update secrets * update generated code to the latest API definition * update secrets baseline * merge with master * merge with master * merge with master * update code to the latest SDK level * address some review comments * address PR comments * address PR comments * update to latest sdk level * update to latest sdk level * update to latest sdk level * merge with master * update to the latest sdk level * format test case * regenerate the code with generator fixes * regenerate code * fix "inputs" and "settings" properties --------- Co-authored-by: dvesperini Co-authored-by: knee-na <130502432+knee-na@users.noreply.github.com> Co-authored-by: Mark-Kulube --- .secrets.baseline | 44 +++---- examples/ibm-project/README.md | 4 +- examples/ibm-project/main.tf | 8 +- go.mod | 2 +- go.sum | 6 +- .../project/data_source_ibm_project_config.go | 53 ++++---- .../data_source_ibm_project_config_test.go | 4 +- .../data_source_ibm_project_environment.go | 24 ++-- ibm/service/project/resource_ibm_project.go | 33 ++--- .../project/resource_ibm_project_config.go | 113 ++++++++---------- .../resource_ibm_project_environment.go | 54 ++++----- website/docs/d/project_config.html.markdown | 12 +- .../docs/d/project_environment.html.markdown | 7 +- website/docs/r/project_config.html.markdown | 18 +-- .../docs/r/project_environment.html.markdown | 3 +- 15 files changed, 159 insertions(+), 226 deletions(-) diff --git a/.secrets.baseline b/.secrets.baseline index 3a62206e9a..0d0d86addf 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "go.mod|go.sum|.*.map|^.secrets.baseline$", "lines": null }, - "generated_at": "2023-11-29T02:05:13Z", + "generated_at": "2023-12-05T09:48:48Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -560,7 +560,7 @@ "hashed_secret": "06d988e96c3d9325c9fbc7c0ef3c6c0f2b4eb8e7", "is_secret": false, "is_verified": false, - "line_number": 45, + "line_number": 41, "type": "Secret Keyword", "verified_result": null } @@ -794,7 +794,7 @@ "hashed_secret": "c427f185ddcb2440be9b77c8e45f1cd487a2e790", "is_secret": false, "is_verified": false, - "line_number": 1449, + "line_number": 1450, "type": "Base64 High Entropy String", "verified_result": null }, @@ -802,7 +802,7 @@ "hashed_secret": "1f7e33de15e22de9d2eaf502df284ed25ca40018", "is_secret": false, "is_verified": false, - "line_number": 1516, + "line_number": 1517, "type": "Secret Keyword", "verified_result": null }, @@ -810,7 +810,7 @@ "hashed_secret": "1f614c2eb6b3da22d89bd1b9fd47d7cb7c8fc670", "is_secret": false, "is_verified": false, - "line_number": 3325, + "line_number": 3326, "type": "Secret Keyword", "verified_result": null }, @@ -818,7 +818,7 @@ "hashed_secret": "7abfce65b8504403afc25c9790f358d513dfbcc6", "is_secret": false, "is_verified": false, - "line_number": 3338, + "line_number": 3339, "type": "Secret Keyword", "verified_result": null }, @@ -826,7 +826,7 @@ "hashed_secret": "0c2d85bf9a9b1579b16f220a4ea8c3d62b2e24b1", "is_secret": false, "is_verified": false, - "line_number": 3379, + "line_number": 3380, "type": "Secret Keyword", "verified_result": null } @@ -864,7 +864,7 @@ "hashed_secret": "c8b6f5ef11b9223ac35a5663975a466ebe7ebba9", "is_secret": false, "is_verified": false, - "line_number": 1807, + "line_number": 1815, "type": "Secret Keyword", "verified_result": null }, @@ -872,7 +872,7 @@ "hashed_secret": "8abf4899c01104241510ba87685ad4de76b0c437", "is_secret": false, "is_verified": false, - "line_number": 1813, + "line_number": 1821, "type": "Secret Keyword", "verified_result": null } @@ -2876,7 +2876,7 @@ "hashed_secret": "3046d9f6cfaaeea6eed9bb7a4ab010fe49b0cfd4", "is_secret": false, "is_verified": false, - "line_number": 334, + "line_number": 335, "type": "Secret Keyword", "verified_result": null }, @@ -2884,7 +2884,7 @@ "hashed_secret": "92f08f2d9a0dc3f0d4cb3796435a48508cf59ecd", "is_secret": false, "is_verified": false, - "line_number": 654, + "line_number": 663, "type": "Secret Keyword", "verified_result": null } @@ -2904,7 +2904,7 @@ "hashed_secret": "3046d9f6cfaaeea6eed9bb7a4ab010fe49b0cfd4", "is_secret": false, "is_verified": false, - "line_number": 119, + "line_number": 120, "type": "Secret Keyword", "verified_result": null }, @@ -2912,7 +2912,7 @@ "hashed_secret": "92f08f2d9a0dc3f0d4cb3796435a48508cf59ecd", "is_secret": false, "is_verified": false, - "line_number": 293, + "line_number": 298, "type": "Secret Keyword", "verified_result": null } @@ -2932,7 +2932,7 @@ "hashed_secret": "3046d9f6cfaaeea6eed9bb7a4ab010fe49b0cfd4", "is_secret": false, "is_verified": false, - "line_number": 236, + "line_number": 237, "type": "Secret Keyword", "verified_result": null }, @@ -2940,7 +2940,7 @@ "hashed_secret": "92f08f2d9a0dc3f0d4cb3796435a48508cf59ecd", "is_secret": false, "is_verified": false, - "line_number": 884, + "line_number": 875, "type": "Secret Keyword", "verified_result": null } @@ -2960,7 +2960,7 @@ "hashed_secret": "3046d9f6cfaaeea6eed9bb7a4ab010fe49b0cfd4", "is_secret": false, "is_verified": false, - "line_number": 72, + "line_number": 73, "type": "Secret Keyword", "verified_result": null }, @@ -2968,7 +2968,7 @@ "hashed_secret": "92f08f2d9a0dc3f0d4cb3796435a48508cf59ecd", "is_secret": false, "is_verified": false, - "line_number": 504, + "line_number": 499, "type": "Secret Keyword", "verified_result": null } @@ -4505,16 +4505,6 @@ "verified_result": null } ], - "website/docs/r/logs_router_tenant.html.markdown": [ - { - "hashed_secret": "d47dcacc720a39e236679ac3e311a0d58bb6519e", - "is_secret": false, - "is_verified": false, - "line_number": 78, - "type": "Secret Keyword", - "verified_result": null - } - ], "website/docs/r/metrics_router_route.html.markdown": [ { "hashed_secret": "d47dcacc720a39e236679ac3e311a0d58bb6519e", diff --git a/examples/ibm-project/README.md b/examples/ibm-project/README.md index 8d4faefa78..479c92419c 100644 --- a/examples/ibm-project/README.md +++ b/examples/ibm-project/README.md @@ -69,8 +69,8 @@ data "project" "project_instance" { project_environment data source: ```hcl -data "ibm_project_environment" "project_environment_instance" { - project_id = ibm_project_environment.project_environment_instance.project_id +data "project_environment" "project_environment_instance" { + project_id = ibm_project.project_instance.id project_environment_id = ibm_project_environment.project_environment_instance.project_environment_id } ``` diff --git a/examples/ibm-project/main.tf b/examples/ibm-project/main.tf index 038e99910a..f07c03de9e 100644 --- a/examples/ibm-project/main.tf +++ b/examples/ibm-project/main.tf @@ -13,13 +13,9 @@ resource "ibm_project_config" "project_config_instance" { api_key = "" } locator_id = "1082e7d2-5e2f-0a11-a3bc-f88a8e1931fc.145be7c1-9ec4-4719-b586-584ee52fbed0-global" - input { + inputs = { name = "app_repo_name" } - setting { - name = "app_repo_name" - value = "static-website-dev-app-repo" - } } } @@ -61,5 +57,5 @@ data "ibm_project" "project_instance" { // Create project_environment data source data "ibm_project_environment" "project_environment_instance" { project_id = ibm_project.project_instance.id - project_environment_id = var.project_environment_project_environment_id + project_environment_id = ibm_project_environment.project_environment_instance.project_environment_id } diff --git a/go.mod b/go.mod index fe7c351529..fdf9de1fb1 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/IBM/logs-router-go-sdk v1.0.0 github.com/IBM/networking-go-sdk v0.42.2 github.com/IBM/platform-services-go-sdk v0.54.0 - github.com/IBM/project-go-sdk v0.1.1 + github.com/IBM/project-go-sdk v0.1.4 github.com/IBM/push-notifications-go-sdk v0.0.0-20210310100607-5790b96c47f5 github.com/IBM/scc-go-sdk/v5 v5.1.3 github.com/IBM/schematics-go-sdk v0.2.2 diff --git a/go.sum b/go.sum index 77c54968b8..f53d313116 100644 --- a/go.sum +++ b/go.sum @@ -100,8 +100,6 @@ github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3 github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.4.4/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/IBM-Cloud/bluemix-go v0.0.0-20231123082353-50e8cc9c6959 h1:dvvI4ybsYx6M7fFGrg3HjlNnYxEBi9jJdSU0JhjJbG8= -github.com/IBM-Cloud/bluemix-go v0.0.0-20231123082353-50e8cc9c6959/go.mod h1:jIGLnIfj+uBv2ALz3rVHzNbNwt0V/bEWNeJKECa8Q+k= github.com/IBM-Cloud/bluemix-go v0.0.0-20231204080125-462fa9e436bc h1:AeooCa6UMWycgKJ9n0do9PEZaNlYZZHqspfwUzPvopc= github.com/IBM-Cloud/bluemix-go v0.0.0-20231204080125-462fa9e436bc/go.mod h1:jIGLnIfj+uBv2ALz3rVHzNbNwt0V/bEWNeJKECa8Q+k= github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20231106114255-c50117860a3c h1:tRS4VuOG3lHNG+yrsh3vZZQDVNLuFJB0oZbTJp9YXds= @@ -161,8 +159,8 @@ github.com/IBM/networking-go-sdk v0.42.2 h1:caqjx4jyFHi10Vlf3skHvlL6K3YJRVstsmCB github.com/IBM/networking-go-sdk v0.42.2/go.mod h1:lTUZwtUkMANMnrLHFIgRhHrkBfwASY/Iho1fabaPHxo= github.com/IBM/platform-services-go-sdk v0.54.0 h1:WjHWm9ZAJvlq07E1WXXtEe+d/B0sazWD6cEWVT7EMLU= github.com/IBM/platform-services-go-sdk v0.54.0/go.mod h1:CWSprvsCsXWvujmBzbtoJSmbRZS9FVV3O594b0t/GiM= -github.com/IBM/project-go-sdk v0.1.1 h1:x1PkGUTkKpgxoXs/6IG4U1mk5BgaPEaRMVpXTs52rE4= -github.com/IBM/project-go-sdk v0.1.1/go.mod h1:lqe0M4cKvABI1iHR1b+KfasVcxQL6nl2VJ8eOyQs8Ig= +github.com/IBM/project-go-sdk v0.1.4 h1:QGehJxpp/QqfrBYSmN2FRYwuGejlHlVscB/9QGQfdLk= +github.com/IBM/project-go-sdk v0.1.4/go.mod h1:lqe0M4cKvABI1iHR1b+KfasVcxQL6nl2VJ8eOyQs8Ig= github.com/IBM/push-notifications-go-sdk v0.0.0-20210310100607-5790b96c47f5 h1:NPUhkoOCRuv3OFWt19PmwjXGGTKlvmbuPg9fUrBUNe4= github.com/IBM/push-notifications-go-sdk v0.0.0-20210310100607-5790b96c47f5/go.mod h1:b07XHUVh0XYnQE9s2mqgjYST1h9buaQNqN4EcKhOsX0= github.com/IBM/sarama v1.41.2 h1:ZDBZfGPHAD4uuAtSv4U22fRZBgst0eEwGFzLj0fb85c= diff --git a/ibm/service/project/data_source_ibm_project_config.go b/ibm/service/project/data_source_ibm_project_config.go index 38ddf87947..8fadc48a9f 100644 --- a/ibm/service/project/data_source_ibm_project_config.go +++ b/ibm/service/project/data_source_ibm_project_config.go @@ -5,6 +5,7 @@ package project import ( "context" + "encoding/json" "fmt" "log" @@ -135,7 +136,7 @@ func DataSourceIbmProjectConfig() *schema.Resource { "workspace_crn": &schema.Schema{ Type: schema.TypeString, Computed: true, - Description: "An existing schematics workspace CRN.", + Description: "An IBM Cloud resource name, which uniquely identifies a resource.", }, "validate_pre_script": &schema.Schema{ Type: schema.TypeList, @@ -377,22 +378,22 @@ func DataSourceIbmProjectConfig() *schema.Resource { "locator_id": &schema.Schema{ Type: schema.TypeString, Computed: true, - Description: "A unique concatenation of catalogID.versionID that identifies the DA in the catalog.", + Description: "A unique concatenation of catalogID.versionID that identifies the DA in the catalog. Either schematics.workspace_crn, definition.locator_id, or both must be specified.", }, "inputs": &schema.Schema{ - Type: schema.TypeList, + Type: schema.TypeMap, Computed: true, Description: "The input variables for configuration definition and environment.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{}, + Elem: &schema.Schema{ + Type: schema.TypeString, }, }, "settings": &schema.Schema{ - Type: schema.TypeList, + Type: schema.TypeMap, Computed: true, - Description: "Schematics environment variables to use to deploy the configuration.Settings are only available if they were specified when the configuration was initially created.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{}, + Description: "Schematics environment variables to use to deploy the configuration. Settings are only available if they were specified when the configuration was initially created.", + Elem: &schema.Schema{ + Type: schema.TypeString, }, }, }, @@ -626,18 +627,26 @@ func dataSourceIbmProjectConfigProjectConfigResponseDefinitionToMap(model *proje } modelMap["locator_id"] = model.LocatorID if model.Inputs != nil { - inputsMap, err := dataSourceIbmProjectConfigInputVariableToMap(model.Inputs) - if err != nil { - return modelMap, err + inputs := make(map[string]interface{}) + for k, v := range model.Inputs { + bytes, err := json.Marshal(v) + if err != nil { + return modelMap, err + } + inputs[k] = string(bytes) } - modelMap["inputs"] = []map[string]interface{}{inputsMap} + modelMap["inputs"] = inputs } if model.Settings != nil { - settingsMap, err := dataSourceIbmProjectConfigProjectConfigSettingToMap(model.Settings) - if err != nil { - return modelMap, err + settings := make(map[string]interface{}) + for k, v := range model.Settings { + bytes, err := json.Marshal(v) + if err != nil { + return modelMap, err + } + settings[k] = string(bytes) } - modelMap["settings"] = []map[string]interface{}{settingsMap} + modelMap["settings"] = settings } return modelMap, nil } @@ -675,13 +684,3 @@ func dataSourceIbmProjectConfigProjectComplianceProfileToMap(model *projectv1.Pr } return modelMap, nil } - -func dataSourceIbmProjectConfigInputVariableToMap(model *projectv1.InputVariable) (map[string]interface{}, error) { - modelMap := make(map[string]interface{}) - return modelMap, nil -} - -func dataSourceIbmProjectConfigProjectConfigSettingToMap(model *projectv1.ProjectConfigSetting) (map[string]interface{}, error) { - modelMap := make(map[string]interface{}) - return modelMap, nil -} diff --git a/ibm/service/project/data_source_ibm_project_config_test.go b/ibm/service/project/data_source_ibm_project_config_test.go index 785e6ff684..e009ba0704 100644 --- a/ibm/service/project/data_source_ibm_project_config_test.go +++ b/ibm/service/project/data_source_ibm_project_config_test.go @@ -56,8 +56,8 @@ func testAccCheckIbmProjectConfigDataSourceConfigBasic() string { authorizations { method = "api_key" api_key = "%s" - } - locator_id = "1082e7d2-5e2f-0a11-a3bc-f88a8e1931fc.cd596f95-95a2-4f21-9b84-477f21fd1e95-global" + } + locator_id = "1082e7d2-5e2f-0a11-a3bc-f88a8e1931fc.cd596f95-95a2-4f21-9b84-477f21fd1e95-global" } lifecycle { ignore_changes = [ diff --git a/ibm/service/project/data_source_ibm_project_environment.go b/ibm/service/project/data_source_ibm_project_environment.go index e42f488a05..dc095eea94 100644 --- a/ibm/service/project/data_source_ibm_project_environment.go +++ b/ibm/service/project/data_source_ibm_project_environment.go @@ -5,6 +5,7 @@ package project import ( "context" + "encoding/json" "fmt" "log" @@ -126,11 +127,11 @@ func DataSourceIbmProjectEnvironment() *schema.Resource { }, }, "inputs": &schema.Schema{ - Type: schema.TypeList, + Type: schema.TypeMap, Computed: true, Description: "The input variables for configuration definition and environment.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{}, + Elem: &schema.Schema{ + Type: schema.TypeString, }, }, "compliance_profile": &schema.Schema{ @@ -265,11 +266,15 @@ func dataSourceIbmProjectEnvironmentEnvironmentDefinitionRequiredPropertiesToMap modelMap["authorizations"] = []map[string]interface{}{authorizationsMap} } if model.Inputs != nil { - inputsMap, err := dataSourceIbmProjectEnvironmentInputVariableToMap(model.Inputs) - if err != nil { - return modelMap, err + inputs := make(map[string]interface{}) + for k, v := range model.Inputs { + bytes, err := json.Marshal(v) + if err != nil { + return modelMap, err + } + inputs[k] = string(bytes) } - modelMap["inputs"] = []map[string]interface{}{inputsMap} + modelMap["inputs"] = inputs } if model.ComplianceProfile != nil { complianceProfileMap, err := dataSourceIbmProjectEnvironmentProjectComplianceProfileToMap(model.ComplianceProfile) @@ -295,11 +300,6 @@ func dataSourceIbmProjectEnvironmentProjectConfigAuthToMap(model *projectv1.Proj return modelMap, nil } -func dataSourceIbmProjectEnvironmentInputVariableToMap(model *projectv1.InputVariable) (map[string]interface{}, error) { - modelMap := make(map[string]interface{}) - return modelMap, nil -} - func dataSourceIbmProjectEnvironmentProjectComplianceProfileToMap(model *projectv1.ProjectComplianceProfile) (map[string]interface{}, error) { modelMap := make(map[string]interface{}) if model.ID != nil { diff --git a/ibm/service/project/resource_ibm_project.go b/ibm/service/project/resource_ibm_project.go index 1147380c19..4e51734983 100644 --- a/ibm/service/project/resource_ibm_project.go +++ b/ibm/service/project/resource_ibm_project.go @@ -5,6 +5,7 @@ package project import ( "context" + "encoding/json" "fmt" "log" @@ -566,19 +567,17 @@ func resourceIbmProjectMapToProjectConfigPrototypeDefinitionBlock(modelMap map[s if modelMap["locator_id"] != nil && modelMap["locator_id"].(string) != "" { model.LocatorID = core.StringPtr(modelMap["locator_id"].(string)) } - if modelMap["inputs"] != nil && len(modelMap["inputs"].([]interface{})) > 0 { - InputsModel, err := resourceIbmProjectMapToInputVariable(modelMap["inputs"].([]interface{})[0].(map[string]interface{})) - if err != nil { - return model, err - } - model.Inputs = InputsModel + if modelMap["inputs"] != nil { + bytes, _ := json.Marshal(modelMap["inputs"].(map[string]interface{})) + newMap := make(map[string]interface{}) + json.Unmarshal(bytes, &newMap) + model.Inputs = newMap } - if modelMap["settings"] != nil && len(modelMap["settings"].([]interface{})) > 0 { - SettingsModel, err := resourceIbmProjectMapToProjectConfigSetting(modelMap["settings"].([]interface{})[0].(map[string]interface{})) - if err != nil { - return model, err - } - model.Settings = SettingsModel + if modelMap["settings"] != nil { + bytes, _ := json.Marshal(modelMap["settings"].(map[string]interface{})) + newMap := make(map[string]interface{}) + json.Unmarshal(bytes, &newMap) + model.Settings = newMap } return model, nil } @@ -617,16 +616,6 @@ func resourceIbmProjectMapToProjectComplianceProfile(modelMap map[string]interfa return model, nil } -func resourceIbmProjectMapToInputVariable(modelMap map[string]interface{}) (*projectv1.InputVariable, error) { - model := &projectv1.InputVariable{} - return model, nil -} - -func resourceIbmProjectMapToProjectConfigSetting(modelMap map[string]interface{}) (*projectv1.ProjectConfigSetting, error) { - model := &projectv1.ProjectConfigSetting{} - return model, nil -} - func resourceIbmProjectMapToSchematicsWorkspace(modelMap map[string]interface{}) (*projectv1.SchematicsWorkspace, error) { model := &projectv1.SchematicsWorkspace{} if modelMap["workspace_crn"] != nil && modelMap["workspace_crn"].(string) != "" { diff --git a/ibm/service/project/resource_ibm_project_config.go b/ibm/service/project/resource_ibm_project_config.go index 5594fbd5b7..161c7a41f1 100644 --- a/ibm/service/project/resource_ibm_project_config.go +++ b/ibm/service/project/resource_ibm_project_config.go @@ -5,6 +5,7 @@ package project import ( "context" + "encoding/json" "fmt" "log" @@ -44,7 +45,7 @@ func ResourceIbmProjectConfig() *schema.Resource { "workspace_crn": &schema.Schema{ Type: schema.TypeString, Optional: true, - Description: "An existing schematics workspace CRN.", + Description: "An IBM Cloud resource name, which uniquely identifies a resource.", }, "validate_pre_script": &schema.Schema{ Type: schema.TypeList, @@ -281,25 +282,19 @@ func ResourceIbmProjectConfig() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - Description: "A unique concatenation of catalogID.versionID that identifies the DA in the catalog.", + Description: "A unique concatenation of catalogID.versionID that identifies the DA in the catalog. Either schematics.workspace_crn, definition.locator_id, or both must be specified.", }, "inputs": &schema.Schema{ - Type: schema.TypeList, - MaxItems: 1, + Type: schema.TypeMap, Optional: true, Description: "The input variables for configuration definition and environment.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{}, - }, + Elem: &schema.Schema{Type: schema.TypeString}, }, "settings": &schema.Schema{ - Type: schema.TypeList, - MaxItems: 1, + Type: schema.TypeMap, Optional: true, - Description: "Schematics environment variables to use to deploy the configuration.Settings are only available if they were specified when the configuration was initially created.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{}, - }, + Description: "Schematics environment variables to use to deploy the configuration. Settings are only available if they were specified when the configuration was initially created.", + Elem: &schema.Schema{Type: schema.TypeString}, }, }, }, @@ -649,19 +644,17 @@ func resourceIbmProjectConfigMapToProjectConfigPrototypeDefinitionBlock(modelMap if modelMap["locator_id"] != nil && modelMap["locator_id"].(string) != "" { model.LocatorID = core.StringPtr(modelMap["locator_id"].(string)) } - if modelMap["inputs"] != nil && len(modelMap["inputs"].([]interface{})) > 0 { - InputsModel, err := resourceIbmProjectConfigMapToInputVariable(modelMap["inputs"].([]interface{})[0].(map[string]interface{})) - if err != nil { - return model, err - } - model.Inputs = InputsModel + if modelMap["inputs"] != nil { + bytes, _ := json.Marshal(modelMap["inputs"].(map[string]interface{})) + newMap := make(map[string]interface{}) + json.Unmarshal(bytes, &newMap) + model.Inputs = newMap } - if modelMap["settings"] != nil && len(modelMap["settings"].([]interface{})) > 0 { - SettingsModel, err := resourceIbmProjectConfigMapToProjectConfigSetting(modelMap["settings"].([]interface{})[0].(map[string]interface{})) - if err != nil { - return model, err - } - model.Settings = SettingsModel + if modelMap["settings"] != nil { + bytes, _ := json.Marshal(modelMap["settings"].(map[string]interface{})) + newMap := make(map[string]interface{}) + json.Unmarshal(bytes, &newMap) + model.Settings = newMap } return model, nil } @@ -700,16 +693,6 @@ func resourceIbmProjectConfigMapToProjectComplianceProfile(modelMap map[string]i return model, nil } -func resourceIbmProjectConfigMapToInputVariable(modelMap map[string]interface{}) (*projectv1.InputVariable, error) { - model := &projectv1.InputVariable{} - return model, nil -} - -func resourceIbmProjectConfigMapToProjectConfigSetting(modelMap map[string]interface{}) (*projectv1.ProjectConfigSetting, error) { - model := &projectv1.ProjectConfigSetting{} - return model, nil -} - func resourceIbmProjectConfigMapToSchematicsWorkspace(modelMap map[string]interface{}) (*projectv1.SchematicsWorkspace, error) { model := &projectv1.SchematicsWorkspace{} if modelMap["workspace_crn"] != nil && modelMap["workspace_crn"].(string) != "" { @@ -746,19 +729,17 @@ func resourceIbmProjectConfigMapToProjectConfigPatchDefinitionBlock(modelMap map if modelMap["locator_id"] != nil && modelMap["locator_id"].(string) != "" { model.LocatorID = core.StringPtr(modelMap["locator_id"].(string)) } - if modelMap["inputs"] != nil && len(modelMap["inputs"].([]interface{})) > 0 { - InputsModel, err := resourceIbmProjectConfigMapToInputVariable(modelMap["inputs"].([]interface{})[0].(map[string]interface{})) - if err != nil { - return model, err - } - model.Inputs = InputsModel + if modelMap["inputs"] != nil { + bytes, _ := json.Marshal(modelMap["inputs"].(map[string]interface{})) + newMap := make(map[string]interface{}) + json.Unmarshal(bytes, &newMap) + model.Inputs = newMap } - if modelMap["settings"] != nil && len(modelMap["settings"].([]interface{})) > 0 { - SettingsModel, err := resourceIbmProjectConfigMapToProjectConfigSetting(modelMap["settings"].([]interface{})[0].(map[string]interface{})) - if err != nil { - return model, err - } - model.Settings = SettingsModel + if modelMap["settings"] != nil { + bytes, _ := json.Marshal(modelMap["settings"].(map[string]interface{})) + newMap := make(map[string]interface{}) + json.Unmarshal(bytes, &newMap) + model.Settings = newMap } return model, nil } @@ -854,20 +835,30 @@ func resourceIbmProjectConfigProjectConfigResponseDefinitionToMap(model *project } modelMap["locator_id"] = model.LocatorID if model.Inputs != nil { - inputsMap, err := resourceIbmProjectConfigInputVariableToMap(model.Inputs) - if err != nil { - return modelMap, err + inputs := make(map[string]interface{}) + for k, v := range model.Inputs { + bytes, err := json.Marshal(v) + if err != nil { + return modelMap, err + } + inputs[k] = string(bytes) } - if len(inputsMap) > 0 { - modelMap["inputs"] = []map[string]interface{}{inputsMap} + if len(inputs) > 0 { + modelMap["inputs"] = inputs } } if model.Settings != nil { - settingsMap, err := resourceIbmProjectConfigProjectConfigSettingToMap(model.Settings) - if err != nil { - return modelMap, err + settings := make(map[string]interface{}) + for k, v := range model.Settings { + bytes, err := json.Marshal(v) + if err != nil { + return modelMap, err + } + settings[k] = string(bytes) + } + if len(settings) > 0 { + modelMap["settings"] = settings } - modelMap["settings"] = []map[string]interface{}{settingsMap} } return modelMap, nil } @@ -906,16 +897,6 @@ func resourceIbmProjectConfigProjectComplianceProfileToMap(model *projectv1.Proj return modelMap, nil } -func resourceIbmProjectConfigInputVariableToMap(model *projectv1.InputVariable) (map[string]interface{}, error) { - modelMap := make(map[string]interface{}) - return modelMap, nil -} - -func resourceIbmProjectConfigProjectConfigSettingToMap(model *projectv1.ProjectConfigSetting) (map[string]interface{}, error) { - modelMap := make(map[string]interface{}) - return modelMap, nil -} - func resourceIbmProjectConfigOutputValueToMap(model *projectv1.OutputValue) (map[string]interface{}, error) { modelMap := make(map[string]interface{}) modelMap["name"] = model.Name diff --git a/ibm/service/project/resource_ibm_project_environment.go b/ibm/service/project/resource_ibm_project_environment.go index 3dda07d3a2..d9fa73b4d9 100644 --- a/ibm/service/project/resource_ibm_project_environment.go +++ b/ibm/service/project/resource_ibm_project_environment.go @@ -5,6 +5,7 @@ package project import ( "context" + "encoding/json" "fmt" "log" @@ -79,13 +80,10 @@ func ResourceIbmProjectEnvironment() *schema.Resource { }, }, "inputs": &schema.Schema{ - Type: schema.TypeList, - MaxItems: 1, + Type: schema.TypeMap, Optional: true, Description: "The input variables for configuration definition and environment.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{}, - }, + Elem: &schema.Schema{Type: schema.TypeString}, }, "compliance_profile": &schema.Schema{ Type: schema.TypeList, @@ -370,12 +368,11 @@ func resourceIbmProjectEnvironmentMapToEnvironmentDefinitionRequiredProperties(m } model.Authorizations = AuthorizationsModel } - if modelMap["inputs"] != nil && len(modelMap["inputs"].([]interface{})) > 0 { - InputsModel, err := resourceIbmProjectEnvironmentMapToInputVariable(modelMap["inputs"].([]interface{})[0].(map[string]interface{})) - if err != nil { - return model, err - } - model.Inputs = InputsModel + if modelMap["inputs"] != nil { + bytes, _ := json.Marshal(modelMap["inputs"].(map[string]interface{})) + newMap := make(map[string]interface{}) + json.Unmarshal(bytes, &newMap) + model.Inputs = newMap } if modelMap["compliance_profile"] != nil && len(modelMap["compliance_profile"].([]interface{})) > 0 { ComplianceProfileModel, err := resourceIbmProjectEnvironmentMapToProjectComplianceProfile(modelMap["compliance_profile"].([]interface{})[0].(map[string]interface{})) @@ -401,11 +398,6 @@ func resourceIbmProjectEnvironmentMapToProjectConfigAuth(modelMap map[string]int return model, nil } -func resourceIbmProjectEnvironmentMapToInputVariable(modelMap map[string]interface{}) (*projectv1.InputVariable, error) { - model := &projectv1.InputVariable{} - return model, nil -} - func resourceIbmProjectEnvironmentMapToProjectComplianceProfile(modelMap map[string]interface{}) (*projectv1.ProjectComplianceProfile, error) { model := &projectv1.ProjectComplianceProfile{} if modelMap["id"] != nil && modelMap["id"].(string) != "" { @@ -441,12 +433,11 @@ func resourceIbmProjectEnvironmentMapToEnvironmentDefinitionProperties(modelMap } model.Authorizations = AuthorizationsModel } - if modelMap["inputs"] != nil && len(modelMap["inputs"].([]interface{})) > 0 { - InputsModel, err := resourceIbmProjectEnvironmentMapToInputVariable(modelMap["inputs"].([]interface{})[0].(map[string]interface{})) - if err != nil { - return model, err - } - model.Inputs = InputsModel + if modelMap["inputs"] != nil { + bytes, _ := json.Marshal(modelMap["inputs"].(map[string]interface{})) + newMap := make(map[string]interface{}) + json.Unmarshal(bytes, &newMap) + model.Inputs = newMap } if modelMap["compliance_profile"] != nil && len(modelMap["compliance_profile"].([]interface{})) > 0 { ComplianceProfileModel, err := resourceIbmProjectEnvironmentMapToProjectComplianceProfile(modelMap["compliance_profile"].([]interface{})[0].(map[string]interface{})) @@ -472,12 +463,16 @@ func resourceIbmProjectEnvironmentEnvironmentDefinitionRequiredPropertiesToMap(m modelMap["authorizations"] = []map[string]interface{}{authorizationsMap} } if model.Inputs != nil { - inputsMap, err := resourceIbmProjectEnvironmentInputVariableToMap(model.Inputs) - if err != nil { - return modelMap, err + inputs := make(map[string]interface{}) + for k, v := range model.Inputs { + bytes, err := json.Marshal(v) + if err != nil { + return modelMap, err + } + inputs[k] = string(bytes) } - if len(inputsMap) > 0 { - modelMap["inputs"] = []map[string]interface{}{inputsMap} + if len(inputs) > 0 { + modelMap["inputs"] = inputs } } if model.ComplianceProfile != nil { @@ -506,11 +501,6 @@ func resourceIbmProjectEnvironmentProjectConfigAuthToMap(model *projectv1.Projec return modelMap, nil } -func resourceIbmProjectEnvironmentInputVariableToMap(model *projectv1.InputVariable) (map[string]interface{}, error) { - modelMap := make(map[string]interface{}) - return modelMap, nil -} - func resourceIbmProjectEnvironmentProjectComplianceProfileToMap(model *projectv1.ProjectComplianceProfile) (map[string]interface{}, error) { modelMap := make(map[string]interface{}) if model.ID != nil { diff --git a/website/docs/d/project_config.html.markdown b/website/docs/d/project_config.html.markdown index 4db739e668..8a3b1e183b 100644 --- a/website/docs/d/project_config.html.markdown +++ b/website/docs/d/project_config.html.markdown @@ -61,14 +61,12 @@ Nested schema for **definition**: * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. * `environment_id` - (String) The ID of the project environment. * Constraints: The maximum length is `128` characters. The value must match regular expression `/^[\\.\\-0-9a-zA-Z]+$/`. - * `inputs` - (List) The input variables for configuration definition and environment. - Nested schema for **inputs**: - * `locator_id` - (Forces new resource, String) A unique concatenation of catalogID.versionID that identifies the DA in the catalog. + * `inputs` - (Map) The input variables for configuration definition and environment. + * `locator_id` - (Forces new resource, String) A unique concatenation of catalogID.versionID that identifies the DA in the catalog. Either schematics.workspace_crn, definition.locator_id, or both must be specified. * Constraints: The maximum length is `512` characters. The minimum length is `1` character. The value must match regular expression `/^(?!\\s)(?!.*\\s$)[\\.0-9a-z-A-Z_-]+$/`. * `name` - (String) The configuration name. It is unique within the account across projects and regions. * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9][a-zA-Z0-9-_ ]*$/`. - * `settings` - (List) Schematics environment variables to use to deploy the configuration.Settings are only available if they were specified when the configuration was initially created. - Nested schema for **settings**: + * `settings` - (Map) Schematics environment variables to use to deploy the configuration. Settings are only available if they were specified when the configuration was initially created. * `is_draft` - (Boolean) The flag that indicates whether the version of the configuration is draft, or active. @@ -151,8 +149,8 @@ Nested schema for **schematics**: * Constraints: The maximum length is `256` characters. The minimum length is `0` characters. The value must match regular expression `/$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. * `type` - (String) The type of the script. * Constraints: The maximum length is `7` characters. The minimum length is `7` characters. The value must match regular expression `/^(ansible)$/`. - * `workspace_crn` - (String) An existing schematics workspace CRN. - * Constraints: The maximum length is `512` characters. The minimum length is `4` characters. The value must match regular expression `/^crn:v[0-9](:([A-Za-z0-9\\-._~!$&'()*+,;=@\/]|%[0-9A-Z]{2})*){8}$/`. + * `workspace_crn` - (String) An IBM Cloud resource name, which uniquely identifies a resource. + * Constraints: The maximum length is `512` characters. The minimum length is `4` characters. The value must match regular expression `/(?!\\s)(?!.*\\s$)^(crn)[^'"`<>{}\\s\\x00-\\x1F]*/`. * `state` - (String) The state of the configuration. * Constraints: Allowable values are: `approved`, `deleted`, `deleting`, `deleting_failed`, `discarded`, `draft`, `deployed`, `deploying_failed`, `deploying`, `superseded`, `undeploying`, `undeploying_failed`, `validated`, `validating`, `validating_failed`. diff --git a/website/docs/d/project_environment.html.markdown b/website/docs/d/project_environment.html.markdown index 3b9420d3fe..e7c6fd774c 100644 --- a/website/docs/d/project_environment.html.markdown +++ b/website/docs/d/project_environment.html.markdown @@ -14,8 +14,8 @@ Provides a read-only data source to retrieve information about a project_environ ```hcl data "ibm_project_environment" "project_environment" { - project_environment_id = ibm_project_environment.project_environment.project_environment_id - project_id = ibm_project_environment.project_environment.project_id + project_environment_id = ibm_project_environment.project_environment_instance.project_environment_id + project_id = ibm_project_environment.project_environment_instance.project_id } ``` @@ -59,8 +59,7 @@ Nested schema for **definition**: * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^(?!\\s)(?!.*\\s$)[^`<>\\x00-\\x1F]*$/`. * `description` - (String) The description of the environment. * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. - * `inputs` - (List) The input variables for configuration definition and environment. - Nested schema for **inputs**: + * `inputs` - (Map) The input variables for configuration definition and environment. * `name` - (String) The name of the environment. It is unique within the account across projects and regions. * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^(?!\\s)(?!.*\\s$)[^'"`<>{}\\x00-\\x1F]+$/`. diff --git a/website/docs/r/project_config.html.markdown b/website/docs/r/project_config.html.markdown index 995dfa3570..86be477768 100644 --- a/website/docs/r/project_config.html.markdown +++ b/website/docs/r/project_config.html.markdown @@ -22,13 +22,9 @@ resource "ibm_project_config" "project_config_instance" { api_key = "" } locator_id = "1082e7d2-5e2f-0a11-a3bc-f88a8e1931fc.145be7c1-9ec4-4719-b586-584ee52fbed0-global" - input { + inputs = { name = "app_repo_name" } - setting { - name = "app_repo_name" - value = "static-website-dev-app-repo" - } } project_id = ibm_project.project_instance.id } @@ -64,14 +60,12 @@ Nested schema for **definition**: * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. * `environment_id` - (Optional, String) The ID of the project environment. * Constraints: The maximum length is `128` characters. The value must match regular expression `/^[\\.\\-0-9a-zA-Z]+$/`. - * `inputs` - (Optional, List) The input variables for configuration definition and environment. - Nested schema for **inputs**: - * `locator_id` - (Required, Forces new resource, String) A unique concatenation of catalogID.versionID that identifies the DA in the catalog. + * `inputs` - (Optional, Map) The input variables for configuration definition and environment. + * `locator_id` - (Required, Forces new resource, String) A unique concatenation of catalogID.versionID that identifies the DA in the catalog. Either schematics.workspace_crn, definition.locator_id, or both must be specified. * Constraints: The maximum length is `512` characters. The minimum length is `1` character. The value must match regular expression `/^(?!\\s)(?!.*\\s$)[\\.0-9a-z-A-Z_-]+$/`. * `name` - (Required, String) The configuration name. It is unique within the account across projects and regions. * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9][a-zA-Z0-9-_ ]*$/`. - * `settings` - (Optional, List) Schematics environment variables to use to deploy the configuration.Settings are only available if they were specified when the configuration was initially created. - Nested schema for **settings**: + * `settings` - (Optional, Map) Schematics environment variables to use to deploy the configuration. Settings are only available if they were specified when the configuration was initially created. * `project_id` - (Required, Forces new resource, String) The unique project ID. * Constraints: The maximum length is `128` characters. The value must match regular expression `/^[\\.\\-0-9a-zA-Z]+$/`. * `schematics` - (Optional, List) A schematics workspace associated to a project configuration, with scripts. @@ -124,8 +118,8 @@ Nested schema for **schematics**: * Constraints: The maximum length is `256` characters. The minimum length is `0` characters. The value must match regular expression `/$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. * `type` - (Computed, String) The type of the script. * Constraints: The maximum length is `7` characters. The minimum length is `7` characters. The value must match regular expression `/^(ansible)$/`. - * `workspace_crn` - (Optional, String) An existing schematics workspace CRN. - * Constraints: The maximum length is `512` characters. The minimum length is `4` characters. The value must match regular expression `/^crn:v[0-9](:([A-Za-z0-9\\-._~!$&'()*+,;=@\/]|%[0-9A-Z]{2})*){8}$/`. + * `workspace_crn` - (Optional, String) An IBM Cloud resource name, which uniquely identifies a resource. + * Constraints: The maximum length is `512` characters. The minimum length is `4` characters. The value must match regular expression `/(?!\\s)(?!.*\\s$)^(crn)[^'"`<>{}\\s\\x00-\\x1F]*/`. ## Attribute Reference diff --git a/website/docs/r/project_environment.html.markdown b/website/docs/r/project_environment.html.markdown index f9783845eb..99299f2fd4 100644 --- a/website/docs/r/project_environment.html.markdown +++ b/website/docs/r/project_environment.html.markdown @@ -54,8 +54,7 @@ Nested schema for **definition**: * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^(?!\\s)(?!.*\\s$)[^`<>\\x00-\\x1F]*$/`. * `description` - (Optional, String) The description of the environment. * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/^$|^(?!\\s)(?!.*\\s$)[^\\x00-\\x1F]*$/`. - * `inputs` - (Optional, List) The input variables for configuration definition and environment. - Nested schema for **inputs**: + * `inputs` - (Optional, Map) The input variables for configuration definition and environment. * `name` - (Required, String) The name of the environment. It is unique within the account across projects and regions. * Constraints: The maximum length is `128` characters. The minimum length is `1` character. The value must match regular expression `/^(?!\\s)(?!.*\\s$)[^'"`<>{}\\x00-\\x1F]+$/`. * `project_id` - (Required, Forces new resource, String) The unique project ID. From b2b59ea59e6e12947c636747d8b9db2c82fcdf81 Mon Sep 17 00:00:00 2001 From: Ian Reyes Date: Sun, 10 Dec 2023 20:03:40 -0500 Subject: [PATCH 04/14] Removed Logs Router Provider Signed-off-by: Ian Reyes --- .secrets.baseline | 18 +- examples/ibm-logs-router/README.md | 81 ------ examples/ibm-logs-router/main.tf | 17 -- examples/ibm-logs-router/outputs.tf | 6 - examples/ibm-logs-router/variables.tf | 33 --- examples/ibm-logs-router/versions.tf | 9 - go.mod | 1 - go.sum | 2 - ibm/conns/config.go | 28 -- ibm/provider/provider.go | 8 - ibm/service/logsrouter/README.md | 11 - .../data_source_ibm_logs_router_tenant.go | 118 -------- ...data_source_ibm_logs_router_tenant_test.go | 44 --- .../resource_ibm_logs_router_tenant.go | 266 ------------------ .../resource_ibm_logs_router_tenant_test.go | 128 --------- website/allowed-subcategories.txt | 1 - .../docs/d/logs_router_tenant.html.markdown | 52 ---- .../docs/r/logs_router_tenant.html.markdown | 60 ---- 18 files changed, 9 insertions(+), 874 deletions(-) delete mode 100644 examples/ibm-logs-router/README.md delete mode 100644 examples/ibm-logs-router/main.tf delete mode 100644 examples/ibm-logs-router/outputs.tf delete mode 100644 examples/ibm-logs-router/variables.tf delete mode 100644 examples/ibm-logs-router/versions.tf delete mode 100644 ibm/service/logsrouter/README.md delete mode 100644 ibm/service/logsrouter/data_source_ibm_logs_router_tenant.go delete mode 100644 ibm/service/logsrouter/data_source_ibm_logs_router_tenant_test.go delete mode 100644 ibm/service/logsrouter/resource_ibm_logs_router_tenant.go delete mode 100644 ibm/service/logsrouter/resource_ibm_logs_router_tenant_test.go delete mode 100644 website/docs/d/logs_router_tenant.html.markdown delete mode 100644 website/docs/r/logs_router_tenant.html.markdown diff --git a/.secrets.baseline b/.secrets.baseline index 0d0d86addf..f846664a78 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "go.mod|go.sum|.*.map|^.secrets.baseline$", "lines": null }, - "generated_at": "2023-12-05T09:48:48Z", + "generated_at": "2023-12-11T01:02:37Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -786,7 +786,7 @@ "hashed_secret": "9184b0c38101bf24d78b2bb0d044deb1d33696fc", "is_secret": false, "is_verified": false, - "line_number": 132, + "line_number": 131, "type": "Secret Keyword", "verified_result": null }, @@ -794,7 +794,7 @@ "hashed_secret": "c427f185ddcb2440be9b77c8e45f1cd487a2e790", "is_secret": false, "is_verified": false, - "line_number": 1450, + "line_number": 1438, "type": "Base64 High Entropy String", "verified_result": null }, @@ -802,7 +802,7 @@ "hashed_secret": "1f7e33de15e22de9d2eaf502df284ed25ca40018", "is_secret": false, "is_verified": false, - "line_number": 1517, + "line_number": 1505, "type": "Secret Keyword", "verified_result": null }, @@ -810,7 +810,7 @@ "hashed_secret": "1f614c2eb6b3da22d89bd1b9fd47d7cb7c8fc670", "is_secret": false, "is_verified": false, - "line_number": 3326, + "line_number": 3298, "type": "Secret Keyword", "verified_result": null }, @@ -818,7 +818,7 @@ "hashed_secret": "7abfce65b8504403afc25c9790f358d513dfbcc6", "is_secret": false, "is_verified": false, - "line_number": 3339, + "line_number": 3311, "type": "Secret Keyword", "verified_result": null }, @@ -826,7 +826,7 @@ "hashed_secret": "0c2d85bf9a9b1579b16f220a4ea8c3d62b2e24b1", "is_secret": false, "is_verified": false, - "line_number": 3380, + "line_number": 3352, "type": "Secret Keyword", "verified_result": null } @@ -864,7 +864,7 @@ "hashed_secret": "c8b6f5ef11b9223ac35a5663975a466ebe7ebba9", "is_secret": false, "is_verified": false, - "line_number": 1815, + "line_number": 1807, "type": "Secret Keyword", "verified_result": null }, @@ -872,7 +872,7 @@ "hashed_secret": "8abf4899c01104241510ba87685ad4de76b0c437", "is_secret": false, "is_verified": false, - "line_number": 1821, + "line_number": 1813, "type": "Secret Keyword", "verified_result": null } diff --git a/examples/ibm-logs-router/README.md b/examples/ibm-logs-router/README.md deleted file mode 100644 index 51da09060a..0000000000 --- a/examples/ibm-logs-router/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# Example for IBM Logs Router V1 - -This example illustrates how to use IBM LogsRouterV1 - -The following types of resources are supported: - -* logs_router_tenant - -## Usage - -To run this example, execute the following commands: - -```bash -$ terraform init -$ terraform plan -$ terraform apply -``` - -Run `terraform destroy` when you don't need these resources. - - -## IbmLogsRouterV1 resources - -logs_router_tenant resource: - -```hcl -resource "logs_router_tenant" "logs_router_tenant_instance" { - target_type = var.logs_router_tenant_target_type - target_host = var.logs_router_tenant_target_host - target_port = var.logs_router_tenant_target_port - target_instance_crn = var.logs_router_tenant_target_instance_crn -} -``` - -## IbmLogsRouterV1 data sources - -logs_router_tenant data source: - -```hcl -data "logs_router_tenant" "logs_router_tenant_instance" { - tenant_id = ibm_logs_router_tenant.logs_router_tenant_instance.id -} -``` - -## Assumptions - -1. TODO - -## Notes - -1. TODO - -## Requirements - -| Name | Version | -|------|---------| -| terraform | ~> 0.12 | - -## Providers - -| Name | Version | -|------|---------| -| ibm | 1.13.1 | - -## Inputs - -| Name | Description | Type | Required | -|------|-------------|------|---------| -| ibmcloud\_api\_key | IBM Cloud API key | `string` | true | -| target_type | Type of log-sink. | `string` | true | -| target_host | Host name of log-sink. | `string` | true | -| target_port | Network port of log sink. | `number` | true | -| target_instance_crn | Cloud resource name of the log-sink target instance. | `string` | true | -| tenant_id | The instance ID of the tenant. | `` | true | - -## Outputs - -| Name | Description | -|------|-------------| -| logs_router_tenant | logs_router_tenant object | -| logs_router_tenant | logs_router_tenant object | diff --git a/examples/ibm-logs-router/main.tf b/examples/ibm-logs-router/main.tf deleted file mode 100644 index 1be39ee095..0000000000 --- a/examples/ibm-logs-router/main.tf +++ /dev/null @@ -1,17 +0,0 @@ -provider "ibm" { - ibmcloud_api_key = var.ibmcloud_api_key -} - -// Provision logs_router_tenant resource instance -resource "ibm_logs_router_tenant" "logs_router_tenant_instance" { - target_type = var.logs_router_tenant_target_type - target_host = var.logs_router_tenant_target_host - target_port = var.logs_router_tenant_target_port - target_instance_crn = var.logs_router_tenant_target_instance_crn -} - -// Create logs_router_tenant data source -data "ibm_logs_router_tenant" "logs_router_tenant_instance" { - tenant_id = ibm_logs_router_tenant.logs_router_tenant_instance.id -} - diff --git a/examples/ibm-logs-router/outputs.tf b/examples/ibm-logs-router/outputs.tf deleted file mode 100644 index 813aeb5bcb..0000000000 --- a/examples/ibm-logs-router/outputs.tf +++ /dev/null @@ -1,6 +0,0 @@ -// This output allows logs_router_tenant data to be referenced by other resources and the terraform CLI -// Modify this output if only certain data should be exposed -output "ibm_logs_router_tenant" { - value = ibm_logs_router_tenant.logs_router_tenant_instance - description = "logs_router_tenant resource instance" -} diff --git a/examples/ibm-logs-router/variables.tf b/examples/ibm-logs-router/variables.tf deleted file mode 100644 index 34a9f372ff..0000000000 --- a/examples/ibm-logs-router/variables.tf +++ /dev/null @@ -1,33 +0,0 @@ -variable "ibmcloud_api_key" { - description = "IBM Cloud API key" - type = string -} - -// Resource arguments for logs_router_tenant -variable "logs_router_tenant_target_type" { - description = "Type of log-sink." - type = string - default = "logdna" -} -variable "logs_router_tenant_target_host" { - description = "Host name of log-sink." - type = string - default = "www.example.com" -} -variable "logs_router_tenant_target_port" { - description = "Network port of log sink." - type = number - default = 10 -} -variable "logs_router_tenant_target_instance_crn" { - description = "Cloud resource name of the log-sink target instance." - type = string - default = "crn:v1:bluemix:public:logdna:us-east:a/36ff82794a734d7580b90c97b0327d28:f08aea7c-dde9-4452-b552-225af4b51eaa::" -} - -// Data source arguments for logs_router_tenant -variable "logs_router_tenant_tenant_id" { - description = "The instance ID of the tenant." - type = string - default = "f3a466c9-c4db-4eee-95cc-ba82db58e2b5" -} diff --git a/examples/ibm-logs-router/versions.tf b/examples/ibm-logs-router/versions.tf deleted file mode 100644 index 54c9d03e8d..0000000000 --- a/examples/ibm-logs-router/versions.tf +++ /dev/null @@ -1,9 +0,0 @@ -terraform { - required_version = ">= 1.0" - required_providers { - ibm = { - source = "IBM-Cloud/ibm" - version = "1.52.0-beta0" - } - } -} diff --git a/go.mod b/go.mod index fdf9de1fb1..4c06cd1d1d 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,6 @@ require ( github.com/IBM/ibm-hpcs-tke-sdk v0.0.0-20211109141421-a4b61b05f7d1 github.com/IBM/ibm-hpcs-uko-sdk v0.0.20-beta github.com/IBM/keyprotect-go-client v0.12.2 - github.com/IBM/logs-router-go-sdk v1.0.0 github.com/IBM/networking-go-sdk v0.42.2 github.com/IBM/platform-services-go-sdk v0.54.0 github.com/IBM/project-go-sdk v0.1.4 diff --git a/go.sum b/go.sum index f53d313116..e9de9e3543 100644 --- a/go.sum +++ b/go.sum @@ -153,8 +153,6 @@ github.com/IBM/ibm-hpcs-uko-sdk v0.0.20-beta/go.mod h1:MLVNHMYoKsvovJZ4v1gQCpIYt github.com/IBM/keyprotect-go-client v0.5.1/go.mod h1:5TwDM/4FRJq1ZOlwQL1xFahLWQ3TveR88VmL1u3njyI= github.com/IBM/keyprotect-go-client v0.12.2 h1:Cjxcqin9Pl0xz3MnxdiVd4v/eIa79xL3hQpSbwOr/DQ= github.com/IBM/keyprotect-go-client v0.12.2/go.mod h1:yr8h2noNgU8vcbs+vhqoXp3Lmv73PI0zAc6VMgFvWwM= -github.com/IBM/logs-router-go-sdk v1.0.0 h1:cGBjf7wJye/WuzFljqN7yB8ToIxLIiffWaQGW9rSTcI= -github.com/IBM/logs-router-go-sdk v1.0.0/go.mod h1:FJpyZctp5DmRms/MtvRUuWBF/CAk76WJzAsJc4EIM/Y= github.com/IBM/networking-go-sdk v0.42.2 h1:caqjx4jyFHi10Vlf3skHvlL6K3YJRVstsmCBmvdyqkA= github.com/IBM/networking-go-sdk v0.42.2/go.mod h1:lTUZwtUkMANMnrLHFIgRhHrkBfwASY/Iho1fabaPHxo= github.com/IBM/platform-services-go-sdk v0.54.0 h1:WjHWm9ZAJvlq07E1WXXtEe+d/B0sazWD6cEWVT7EMLU= diff --git a/ibm/conns/config.go b/ibm/conns/config.go index 88eb394709..ff89bd307f 100644 --- a/ibm/conns/config.go +++ b/ibm/conns/config.go @@ -29,7 +29,6 @@ import ( "github.com/IBM/go-sdk-core/v5/core" cosconfig "github.com/IBM/ibm-cos-sdk-go-config/resourceconfigurationv1" kp "github.com/IBM/keyprotect-go-client" - "github.com/IBM/logs-router-go-sdk/ibmlogsrouteropenapi30v0" cisalertsv1 "github.com/IBM/networking-go-sdk/alertsv1" cisoriginpull "github.com/IBM/networking-go-sdk/authenticatedoriginpullapiv1" cisbotanalyticsv1 "github.com/IBM/networking-go-sdk/botanalyticsv1" @@ -229,7 +228,6 @@ type ClientSession interface { ResourceManagementAPIv2() (managementv2.ResourceManagementAPIv2, error) ResourceControllerAPI() (controller.ResourceControllerAPI, error) ResourceControllerAPIV2() (controllerv2.ResourceControllerAPIV2, error) - IbmLogsRouterOpenApi30V0() (*ibmlogsrouteropenapi30v0.IbmLogsRouterOpenApi30V0, error) SoftLayerSession() *slsession.Session IBMPISession() (*ibmpisession.IBMPISession, error) UserManagementAPI() (usermanagementv2.UserManagementAPI, error) @@ -544,10 +542,6 @@ type clientSession struct { secretsManagerClient *secretsmanagerv2.SecretsManagerV2 secretsManagerClientErr error - // Logs Routing - ibmLogsRouterOpenApi30Client *ibmlogsrouteropenapi30v0.IbmLogsRouterOpenApi30V0 - ibmLogsRouterOpenApi30ClientErr error - // Schematics service options schematicsClient *schematicsv1.SchematicsV1 schematicsClientErr error @@ -1175,11 +1169,6 @@ func (session clientSession) MetricsRouterV3() (*metricsrouterv3.MetricsRouterV3 return session.metricsRouterClient, session.metricsRouterClientErr } -// Logs Router API -func (session clientSession) IbmLogsRouterOpenApi30V0() (*ibmlogsrouteropenapi30v0.IbmLogsRouterOpenApi30V0, error) { - return session.ibmLogsRouterOpenApi30Client, session.ibmLogsRouterOpenApi30ClientErr -} - func (session clientSession) ESschemaRegistrySession() (*schemaregistryv1.SchemaregistryV1, error) { return session.esSchemaRegistryClient, session.esSchemaRegistryErr } @@ -1307,7 +1296,6 @@ func (c *Config) ClientSession() (interface{}, error) { session.cdToolchainClientErr = errEmptyBluemixCredentials session.codeEngineClientErr = errEmptyBluemixCredentials session.projectClientErr = errEmptyBluemixCredentials - session.ibmLogsRouterOpenApi30ClientErr = errEmptyBluemixCredentials return session, nil } @@ -1690,22 +1678,6 @@ func (c *Config) ClientSession() (interface{}, error) { }) } - // LOGS ROUTER service - ibmLogsRouterOpenApi30ClientOptions := &ibmlogsrouteropenapi30v0.IbmLogsRouterOpenApi30V0Options{ - Authenticator: authenticator, - } - session.ibmLogsRouterOpenApi30Client, err = ibmlogsrouteropenapi30v0.NewIbmLogsRouterOpenApi30V0(ibmLogsRouterOpenApi30ClientOptions) - if err == nil { - // Enable retries for API calls - session.ibmLogsRouterOpenApi30Client.Service.EnableRetries(c.RetryCount, c.RetryDelay) - // Add custom header for analytics - session.ibmLogsRouterOpenApi30Client.SetDefaultHeaders(gohttp.Header{ - "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, - }) - } else { - session.ibmLogsRouterOpenApi30ClientErr = fmt.Errorf("Error occurred while configuring IBM logs-router service: %q", err) - } - // ATRACKER Version 2 var atrackerClientV2URL string var atrackerURLV2Err error diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go index aa758ebf66..9a0e61277b 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -38,7 +38,6 @@ import ( "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/iampolicy" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/kms" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/kubernetes" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/logsrouter" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/metricsrouter" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/power" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/project" @@ -744,9 +743,6 @@ func Provider() *schema.Provider { "ibm_metrics_router_targets": metricsrouter.DataSourceIBMMetricsRouterTargets(), "ibm_metrics_router_routes": metricsrouter.DataSourceIBMMetricsRouterRoutes(), - // Logs Router - "ibm_logs_router_tenant": logsrouter.DataSourceIbmLogsRouterTenant(), - // Security and Complaince Center(soon to be deprecated) "ibm_scc_account_location": scc.DataSourceIBMSccAccountLocation(), "ibm_scc_account_locations": scc.DataSourceIBMSccAccountLocations(), @@ -1280,9 +1276,6 @@ func Provider() *schema.Provider { "ibm_metrics_router_route": metricsrouter.ResourceIBMMetricsRouterRoute(), "ibm_metrics_router_settings": metricsrouter.ResourceIBMMetricsRouterSettings(), - // Logs Router - "ibm_logs_router_tenant": logsrouter.ResourceIbmLogsRouterTenant(), - // Security and Compliance Center(soon to be deprecated) "ibm_scc_account_settings": scc.ResourceIBMSccAccountSettings(), "ibm_scc_rule_attachment": scc.ResourceIBMSccRuleAttachment(), @@ -1547,7 +1540,6 @@ func Validator() validate.ValidatorDict { "ibm_metrics_router_target": metricsrouter.ResourceIBMMetricsRouterTargetValidator(), "ibm_metrics_router_route": metricsrouter.ResourceIBMMetricsRouterRouteValidator(), "ibm_metrics_router_settings": metricsrouter.ResourceIBMMetricsRouterSettingsValidator(), - "ibm_logs_router_tenant": logsrouter.ResourceIbmLogsRouterTenantValidator(), "ibm_satellite_endpoint": satellite.ResourceIBMSatelliteEndpointValidator(), "ibm_cbr_zone": contextbasedrestrictions.ResourceIBMCbrZoneValidator(), "ibm_cbr_rule": contextbasedrestrictions.ResourceIBMCbrRuleValidator(), diff --git a/ibm/service/logsrouter/README.md b/ibm/service/logsrouter/README.md deleted file mode 100644 index 350106c42d..0000000000 --- a/ibm/service/logsrouter/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Terraform IBM Provider - -This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. - - -## Handy Links -* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! -* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) -* IBM Provider Docs: [One of the resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/logs_router_tenant) -* IBM API Docs: [IBM API Docs for IBM Cloud Logs Router](https://test.cloud.ibm.com/apidocs/logs-router-service-api) -* IBM SDK: [IBM SDK for IBM Cloud Logs Router](https://github.com/IBM/logs-router-go-sdk) diff --git a/ibm/service/logsrouter/data_source_ibm_logs_router_tenant.go b/ibm/service/logsrouter/data_source_ibm_logs_router_tenant.go deleted file mode 100644 index db12580145..0000000000 --- a/ibm/service/logsrouter/data_source_ibm_logs_router_tenant.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright IBM Corp. 2023 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package logsrouter - -import ( - "context" - "fmt" - "log" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" - "github.com/IBM/logs-router-go-sdk/ibmlogsrouteropenapi30v0" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/go-openapi/strfmt" -) - -func DataSourceIbmLogsRouterTenant() *schema.Resource { - return &schema.Resource{ - ReadContext: dataSourceIbmLogsRouterTenantRead, - - Schema: map[string]*schema.Schema{ - "tenant_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - Description: "The instance ID of the tenant.", - }, - "account_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "The account ID the tenant belongs to.", - }, - "target_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Type of log-sink.", - }, - "target_host": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Host name of log-sink.", - }, - "target_port": &schema.Schema{ - Type: schema.TypeInt, - Computed: true, - Description: "Network port of log sink.", - }, - "target_instance_crn": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Cloud resource name of the log-sink target instance.", - }, - "created_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "Time stamp the tenant was originally created.", - }, - "updated_at": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Description: "time stamp the tenant was last updated.", - }, - }, - } -} - -func dataSourceIbmLogsRouterTenantRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - ibmLogsRouterOpenApi30Client, err := meta.(conns.ClientSession).IbmLogsRouterOpenApi30V0() - if err != nil { - return diag.FromErr(err) - } - - getTenantDetailOptions := &ibmlogsrouteropenapi30v0.GetTenantDetailOptions{} - - getTenantDetailOptions.SetTenantID(core.UUIDPtr(strfmt.UUID(d.Get("tenant_id").(string)))) - - tenantDetailsResponse, response, err := ibmLogsRouterOpenApi30Client.GetTenantDetailWithContext(context, getTenantDetailOptions) - if err != nil { - log.Printf("[DEBUG] GetTenantDetailWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("GetTenantDetailWithContext failed %s\n%s", err, response)) - } - - d.SetId(fmt.Sprintf("%s", *getTenantDetailOptions.TenantID)) - - if err = d.Set("account_id", tenantDetailsResponse.AccountID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting account_id: %s", err)) - } - - if err = d.Set("target_type", tenantDetailsResponse.TargetType); err != nil { - return diag.FromErr(fmt.Errorf("Error setting target_type: %s", err)) - } - - if err = d.Set("target_host", tenantDetailsResponse.TargetHost); err != nil { - return diag.FromErr(fmt.Errorf("Error setting target_host: %s", err)) - } - - if err = d.Set("target_port", flex.IntValue(tenantDetailsResponse.TargetPort)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting target_port: %s", err)) - } - - if err = d.Set("target_instance_crn", tenantDetailsResponse.TargetInstanceCrn); err != nil { - return diag.FromErr(fmt.Errorf("Error setting target_instance_crn: %s", err)) - } - - if err = d.Set("created_at", tenantDetailsResponse.CreatedAt); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) - } - - if err = d.Set("updated_at", tenantDetailsResponse.UpdatedAt); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) - } - - return nil -} diff --git a/ibm/service/logsrouter/data_source_ibm_logs_router_tenant_test.go b/ibm/service/logsrouter/data_source_ibm_logs_router_tenant_test.go deleted file mode 100644 index 597acdbded..0000000000 --- a/ibm/service/logsrouter/data_source_ibm_logs_router_tenant_test.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright IBM Corp. 2023 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package logsrouter_test - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - - acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" -) - -func TestAccIbmLogsRouterTenantDataSourceBasic(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { acc.TestAccPreCheck(t) }, - Providers: acc.TestAccProviders, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIbmLogsRouterTenantDataSourceConfigBasic(), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.ibm_logs_router_tenant.logs_router_tenant_instance", "id"), - resource.TestCheckResourceAttrSet("data.ibm_logs_router_tenant.logs_router_tenant_instance", "tenant_id"), - ), - }, - }, - }) -} - -func testAccCheckIbmLogsRouterTenantDataSourceConfigBasic() string { - return fmt.Sprintf(` - resource "ibm_logs_router_tenant" "logs_router_tenant_instance" { - target_type = "logdna" - target_host = "tf-target-host-01" - target_port = 42 - target_instance_crn = "crn:v1:bluemix:public:logdna:eu-de:a/3516b8fa0a174a71899f5affa4f18d78:3517d2ed-9429-af34-ad52-34278391cbca::" - access_credential = "test-credential" - } - data "ibm_logs_router_tenant" "logs_router_tenant_instance" { - tenant_id = ibm_logs_router_tenant.logs_router_tenant_instance.id - } - `) -} diff --git a/ibm/service/logsrouter/resource_ibm_logs_router_tenant.go b/ibm/service/logsrouter/resource_ibm_logs_router_tenant.go deleted file mode 100644 index 02da4c81c0..0000000000 --- a/ibm/service/logsrouter/resource_ibm_logs_router_tenant.go +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright IBM Corp. 2023 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package logsrouter - -import ( - "context" - "fmt" - "log" - - "github.com/go-openapi/strfmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/logs-router-go-sdk/ibmlogsrouteropenapi30v0" -) - -func ResourceIbmLogsRouterTenant() *schema.Resource { - return &schema.Resource{ - CreateContext: resourceIbmLogsRouterTenantCreate, - ReadContext: resourceIbmLogsRouterTenantRead, - UpdateContext: resourceIbmLogsRouterTenantUpdate, - DeleteContext: resourceIbmLogsRouterTenantDelete, - Importer: &schema.ResourceImporter{}, - - Schema: map[string]*schema.Schema{ - "target_type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validate.InvokeValidator("ibm_logs_router_tenant", "target_type"), - Description: "Type of log-sink.", - }, - "target_host": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validate.InvokeValidator("ibm_logs_router_tenant", "target_host"), - Description: "Host name of log-sink.", - }, - "target_port": { - Type: schema.TypeInt, - Required: true, - Description: "Network port of log sink.", - }, - "target_instance_crn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validate.InvokeValidator("ibm_logs_router_tenant", "target_instance_crn"), - Description: "Cloud resource name of the log-sink target instance.", - }, - "access_credential": { - Type: schema.TypeString, - Required: true, - Sensitive: true, - ValidateFunc: validate.InvokeValidator("ibm_logs_router_tenant", "access_credential"), - Description: "Secret to connect to the log-sink", - }, - "account_id": { - Type: schema.TypeString, - Computed: true, - Description: "The account ID the tenant belongs to.", - }, - "created_at": { - Type: schema.TypeString, - Computed: true, - Description: "Time stamp the tenant was originally created.", - }, - "updated_at": { - Type: schema.TypeString, - Computed: true, - Description: "time stamp the tenant was last updated.", - }, - }, - } -} - -func ResourceIbmLogsRouterTenantValidator() *validate.ResourceValidator { - validateSchema := make([]validate.ValidateSchema, 0) - validateSchema = append(validateSchema, - validate.ValidateSchema{ - Identifier: "target_type", - ValidateFunctionIdentifier: validate.ValidateRegexpLen, - Type: validate.TypeString, - Required: true, - Regexp: `[a-z,A-Z,0-9,-]`, - MinValueLength: 1, - MaxValueLength: 32, - }, - validate.ValidateSchema{ - Identifier: "target_host", - ValidateFunctionIdentifier: validate.ValidateRegexpLen, - Type: validate.TypeString, - Required: true, - Regexp: `[a-z,A-Z,0-9,-,.]`, - MinValueLength: 1, - MaxValueLength: 256, - }, - validate.ValidateSchema{ - Identifier: "target_instance_crn", - ValidateFunctionIdentifier: validate.ValidateRegexpLen, - Type: validate.TypeString, - Required: true, - Regexp: `[a-z,A-Z,0-9,:,-]`, - MinValueLength: 1, - MaxValueLength: 256, - }, - validate.ValidateSchema{ - Identifier: "access_credential", - ValidateFunctionIdentifier: validate.ValidateRegexpLen, - Type: validate.TypeString, - Required: true, - Regexp: `[a-z,A-Z,0-9,-\\.;!?]`, - MinValueLength: 10, - MaxValueLength: 50, - }, - ) - - resourceValidator := validate.ResourceValidator{ResourceName: "ibm_logs_router_tenant", Schema: validateSchema} - return &resourceValidator -} - -func resourceIbmLogsRouterTenantCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - ibmLogsRouterOpenApi30Client, err := meta.(conns.ClientSession).IbmLogsRouterOpenApi30V0() - if err != nil { - return diag.FromErr(err) - } - - createTenantOptions := &ibmlogsrouteropenapi30v0.CreateTenantOptions{} - - createTenantOptions.SetTargetType(d.Get("target_type").(string)) - createTenantOptions.SetTargetHost(d.Get("target_host").(string)) - createTenantOptions.SetTargetPort(int64(d.Get("target_port").(int))) - createTenantOptions.SetAccessCredential(d.Get("access_credential").(string)) - createTenantOptions.SetTargetInstanceCrn(d.Get("target_instance_crn").(string)) - - tenantDetailsResponse, response, err := ibmLogsRouterOpenApi30Client.CreateTenantWithContext(context, createTenantOptions) - if err != nil { - log.Printf("[DEBUG] CreateTenantWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("CreateTenantWithContext failed %s\n%s", err, response)) - } - - d.SetId(tenantDetailsResponse.ID.String()) - - return resourceIbmLogsRouterTenantRead(context, d, meta) -} - -func resourceIbmLogsRouterTenantRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - ibmLogsRouterOpenApi30Client, err := meta.(conns.ClientSession).IbmLogsRouterOpenApi30V0() - if err != nil { - return diag.FromErr(err) - } - - getTenantDetailOptions := &ibmlogsrouteropenapi30v0.GetTenantDetailOptions{} - tenantId := strfmt.UUID(d.Id()) - getTenantDetailOptions.SetTenantID(&tenantId) - - tenantDetailsResponse, response, err := ibmLogsRouterOpenApi30Client.GetTenantDetailWithContext(context, getTenantDetailOptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - log.Printf("[DEBUG] GetTenantDetailWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("GetTenantDetailWithContext failed %s\n%s", err, response)) - } - - if err = d.Set("target_type", tenantDetailsResponse.TargetType); err != nil { - return diag.FromErr(fmt.Errorf("Error setting target_type: %s", err)) - } - if err = d.Set("target_host", tenantDetailsResponse.TargetHost); err != nil { - return diag.FromErr(fmt.Errorf("Error setting target_host: %s", err)) - } - if err = d.Set("target_port", flex.IntValue(tenantDetailsResponse.TargetPort)); err != nil { - return diag.FromErr(fmt.Errorf("Error setting target_port: %s", err)) - } - if err = d.Set("target_instance_crn", tenantDetailsResponse.TargetInstanceCrn); err != nil { - return diag.FromErr(fmt.Errorf("Error setting target_instance_crn: %s", err)) - } - if !core.IsNil(tenantDetailsResponse.AccountID) { - if err = d.Set("account_id", tenantDetailsResponse.AccountID); err != nil { - return diag.FromErr(fmt.Errorf("Error setting account_id: %s", err)) - } - } - if !core.IsNil(tenantDetailsResponse.CreatedAt) { - if err = d.Set("created_at", tenantDetailsResponse.CreatedAt); err != nil { - return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) - } - } - if !core.IsNil(tenantDetailsResponse.UpdatedAt) { - if err = d.Set("updated_at", tenantDetailsResponse.UpdatedAt); err != nil { - return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) - } - } - - return nil -} - -func resourceIbmLogsRouterTenantUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - ibmLogsRouterOpenApi30Client, err := meta.(conns.ClientSession).IbmLogsRouterOpenApi30V0() - if err != nil { - return diag.FromErr(err) - } - - updateTargetOptions := &ibmlogsrouteropenapi30v0.UpdateTargetOptions{} - tenantId := strfmt.UUID(d.Id()) - updateTargetOptions.SetTenantID(&tenantId) - - hasChange := false - - patchVals := &ibmlogsrouteropenapi30v0.TenantDetailsResponsePatch{} - if d.HasChange("target_host") { - newTargetHost := d.Get("target_host").(string) - patchVals.TargetHost = &newTargetHost - hasChange = true - } - if d.HasChange("target_port") { - newTargetPort := int64(d.Get("target_port").(int)) - patchVals.TargetPort = &newTargetPort - hasChange = true - } - if d.HasChange("access_credential") { - newAccessCredential := d.Get("access_credential").(string) - patchVals.AccessCredential = &newAccessCredential - hasChange = true - } - if d.HasChange("target_instance_crn") { - newTargetInstanceCrn := d.Get("target_instance_crn").(string) - patchVals.TargetInstanceCrn = &newTargetInstanceCrn - hasChange = true - } - - if hasChange { - updateTargetOptions.TenantDetailsResponsePatch, _ = patchVals.AsPatch() - _, response, err := ibmLogsRouterOpenApi30Client.UpdateTargetWithContext(context, updateTargetOptions) - if err != nil { - log.Printf("[DEBUG] UpdateTargetWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("UpdateTargetWithContext failed %s\n%s", err, response)) - } - } - - return resourceIbmLogsRouterTenantRead(context, d, meta) -} - -func resourceIbmLogsRouterTenantDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - ibmLogsRouterOpenApi30Client, err := meta.(conns.ClientSession).IbmLogsRouterOpenApi30V0() - if err != nil { - return diag.FromErr(err) - } - - deleteTenantOptions := &ibmlogsrouteropenapi30v0.DeleteTenantOptions{} - tenantId := strfmt.UUID(d.Id()) - deleteTenantOptions.SetTenantID(&tenantId) - - _, response, err := ibmLogsRouterOpenApi30Client.DeleteTenantWithContext(context, deleteTenantOptions) - if err != nil { - log.Printf("[DEBUG] DeleteTenantWithContext failed %s\n%s", err, response) - return diag.FromErr(fmt.Errorf("DeleteTenantWithContext failed %s\n%s", err, response)) - } - - d.SetId("") - - return nil -} diff --git a/ibm/service/logsrouter/resource_ibm_logs_router_tenant_test.go b/ibm/service/logsrouter/resource_ibm_logs_router_tenant_test.go deleted file mode 100644 index a625776d49..0000000000 --- a/ibm/service/logsrouter/resource_ibm_logs_router_tenant_test.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright IBM Corp. 2023 All Rights Reserved. -// Licensed under the Mozilla Public License v2.0 - -package logsrouter_test - -import ( - "fmt" - "testing" - - "github.com/go-openapi/strfmt" - "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" - - acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" - "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" - "github.com/IBM/logs-router-go-sdk/ibmlogsrouteropenapi30v0" -) - -func TestAccIbmLogsRouterTenantBasic(t *testing.T) { - var conf ibmlogsrouteropenapi30v0.TenantDetailsResponse - targetType := fmt.Sprintf("logdna") - targetHost := fmt.Sprintf("tf-target-host-%d", acctest.RandIntRange(10, 100)) - targetPort := fmt.Sprintf("%d", acctest.RandIntRange(10, 100)) - targetInstanceCrn := fmt.Sprintf("crn:v1:bluemix:public:logdna:eu-de:a/3516b8fa0a174a71899f5affa4f18d78:3517d2ed-9429-af34-ad52-34278391cbc8::") - targetTypeUpdate := fmt.Sprintf("logdna") - targetHostUpdate := fmt.Sprintf("tf-target-host-%d", acctest.RandIntRange(10, 100)) - targetPortUpdate := fmt.Sprintf("%d", acctest.RandIntRange(10, 100)) - targetInstanceCrnUpdate := fmt.Sprintf("crn:v1:bluemix:public:logdna:eu-de:a/3516b8fa0a174a71899f5affa4f18d78:3517d2ed-9429-af34-ad52-34278391cbc8::") - - resource.Test(t, resource.TestCase{ - PreCheck: func() { acc.TestAccPreCheck(t) }, - Providers: acc.TestAccProviders, - CheckDestroy: testAccCheckIbmLogsRouterTenantDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIbmLogsRouterTenantConfigBasic(targetType, targetHost, targetPort, targetInstanceCrn), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIbmLogsRouterTenantExists("ibm_logs_router_tenant.logs_router_tenant_instance", conf), - resource.TestCheckResourceAttr("ibm_logs_router_tenant.logs_router_tenant_instance", "target_type", targetType), - resource.TestCheckResourceAttr("ibm_logs_router_tenant.logs_router_tenant_instance", "target_host", targetHost), - resource.TestCheckResourceAttr("ibm_logs_router_tenant.logs_router_tenant_instance", "target_instance_crn", targetInstanceCrn), - ), - }, - resource.TestStep{ - Config: testAccCheckIbmLogsRouterTenantConfigBasic(targetTypeUpdate, targetHostUpdate, targetPortUpdate, targetInstanceCrnUpdate), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("ibm_logs_router_tenant.logs_router_tenant_instance", "target_type", targetTypeUpdate), - resource.TestCheckResourceAttr("ibm_logs_router_tenant.logs_router_tenant_instance", "target_host", targetHostUpdate), - resource.TestCheckResourceAttr("ibm_logs_router_tenant.logs_router_tenant_instance", "target_port", targetPortUpdate), - resource.TestCheckResourceAttr("ibm_logs_router_tenant.logs_router_tenant_instance", "target_instance_crn", targetInstanceCrnUpdate), - ), - }, - resource.TestStep{ - ResourceName: "ibm_logs_router_tenant.logs_router_tenant_instance", //"ibm_logs_router_tenant.logs_router_tenant", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"access_credential"}, - }, - }, - }) -} - -func testAccCheckIbmLogsRouterTenantConfigBasic(targetType string, targetHost string, targetPort string, targetInstanceCrn string) string { - return fmt.Sprintf(` - resource "ibm_logs_router_tenant" "logs_router_tenant_instance" { - target_type = "%s" - target_host = "%s" - target_port = %s - target_instance_crn = "%s" - access_credential = "test-credential" - } - `, targetType, targetHost, targetPort, targetInstanceCrn) -} - -func testAccCheckIbmLogsRouterTenantExists(n string, obj ibmlogsrouteropenapi30v0.TenantDetailsResponse) resource.TestCheckFunc { - - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - ibmLogsRouterOpenApi30Client, err := acc.TestAccProvider.Meta().(conns.ClientSession).IbmLogsRouterOpenApi30V0() - if err != nil { - return err - } - - getTenantDetailOptions := &ibmlogsrouteropenapi30v0.GetTenantDetailOptions{} - tenantId := strfmt.UUID(rs.Primary.ID) - getTenantDetailOptions.SetTenantID(&tenantId) - - tenantDetailsResponse, _, err := ibmLogsRouterOpenApi30Client.GetTenantDetail(getTenantDetailOptions) - if err != nil { - return err - } - - obj = *tenantDetailsResponse - return nil - } -} - -func testAccCheckIbmLogsRouterTenantDestroy(s *terraform.State) error { - ibmLogsRouterOpenApi30Client, err := acc.TestAccProvider.Meta().(conns.ClientSession).IbmLogsRouterOpenApi30V0() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_logs_router_tenant" { - continue - } - - getTenantDetailOptions := &ibmlogsrouteropenapi30v0.GetTenantDetailOptions{} - tenantId := strfmt.UUID(rs.Primary.ID) - getTenantDetailOptions.SetTenantID(&tenantId) - - // Try to find the key - _, response, err := ibmLogsRouterOpenApi30Client.GetTenantDetail(getTenantDetailOptions) - - if err == nil { - return fmt.Errorf("logs_router_tenant still exists: %s", rs.Primary.ID) - } else if response.StatusCode != 404 { - return fmt.Errorf("Error checking for logs_router_tenant (%s) has been destroyed: %s", rs.Primary.ID, err) - } - } - - return nil -} diff --git a/website/allowed-subcategories.txt b/website/allowed-subcategories.txt index 7410d43146..1e97423139 100644 --- a/website/allowed-subcategories.txt +++ b/website/allowed-subcategories.txt @@ -25,7 +25,6 @@ Identity & Access Management (IAM) Internet services Key Management Service Kubernetes Service -Logs Router Metrics Router Object Storage Power Systems diff --git a/website/docs/d/logs_router_tenant.html.markdown b/website/docs/d/logs_router_tenant.html.markdown deleted file mode 100644 index 0ff47b87b3..0000000000 --- a/website/docs/d/logs_router_tenant.html.markdown +++ /dev/null @@ -1,52 +0,0 @@ ---- -layout: "ibm" -page_title: "IBM : ibm_logs_router_tenant" -description: |- - Get information about logs_router_tenant -subcategory: "Logs Router" ---- - -# ibm_logs_router_tenant - -Provides a read-only data source to retrieve information about a logs_router_tenant. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. - -## Example Usage - -```hcl -data "ibm_logs_router_tenant" "logs_router_tenant" { - tenant_id = "f3a466c9-c4db-4eee-95cc-ba82db58e2b5" -} -``` - -## Argument Reference - -You can specify the following arguments for this data source. - -* `tenant_id` - (Required, Forces new resource, String) The instance ID of the tenant. - * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/[A-F,0-9,-]/`. - -## Attribute Reference - -After your data source is created, you can read values from the following attributes. - -* `id` - The unique identifier of the logs_router_tenant. -* `account_id` - (String) The account ID the tenant belongs to. - * Constraints: The maximum length is `32` characters. The minimum length is `32` characters. The value must match regular expression `/[a-z,A-Z,0-9,-]/`. - -* `created_at` - (String) Time stamp the tenant was originally created. - * Constraints: The maximum length is `36` characters. The minimum length is `1` character. The value must match regular expression `/[0-9,:,.,-,T,Z]/`. - -* `target_host` - (String) Host name of log-sink. - * Constraints: The maximum length is `256` characters. The minimum length is `1` character. The value must match regular expression `/[a-z,A-Z,0-9,-,.]/`. - -* `target_instance_crn` - (String) Cloud resource name of the log-sink target instance. - * Constraints: The maximum length is `256` characters. The minimum length is `1` character. The value must match regular expression `/[a-z,A-Z,0-9,:,-]/`. - -* `target_port` - (Integer) Network port of log sink. - -* `target_type` - (String) Type of log-sink. - * Constraints: The maximum length is `32` characters. The minimum length is `1` character. The value must match regular expression `/[a-z,A-Z,0-9,-]/`. - -* `updated_at` - (String) time stamp the tenant was last updated. - * Constraints: The maximum length is `36` characters. The minimum length is `1` character. The value must match regular expression `/[0-9,:,.,-,T,Z]/`. - diff --git a/website/docs/r/logs_router_tenant.html.markdown b/website/docs/r/logs_router_tenant.html.markdown deleted file mode 100644 index 0a193468d8..0000000000 --- a/website/docs/r/logs_router_tenant.html.markdown +++ /dev/null @@ -1,60 +0,0 @@ ---- -layout: "ibm" -page_title: "IBM : ibm_logs_router_tenant" -description: |- - Manages logs_router_tenant. -subcategory: "Logs Router" ---- - -# ibm_logs_router_tenant - -Create, update, and delete logs_router_tenants with this resource. - -## Example Usage - -```hcl -resource "ibm_logs_router_tenant" "logs_router_tenant_instance" { - target_host = "www.example.com" - target_instance_crn = "crn:v1:bluemix:public:logdna:eu-de:a/3516b8fa0a174a71899f5affa4f18d78:3517d2ed-9429-af34-ad52-34278391cbc8::" - target_port = 10 - target_type = "logdna" -} -``` - -## Argument Reference - -You can specify the following arguments for this resource. - -* `target_host` - (Required, String) Host name of log-sink. - * Constraints: The maximum length is `256` characters. The minimum length is `1` character. The value must match regular expression `/[a-z,A-Z,0-9,-,.]/`. -* `target_instance_crn` - (Required, String) Cloud resource name of the log-sink target instance. - * Constraints: The maximum length is `256` characters. The minimum length is `1` character. The value must match regular expression `/[a-z,A-Z,0-9,:,-]/`. -* `target_port` - (Required, Integer) Network port of log sink. -* `target_type` - (Required, String) Type of log-sink. - * Constraints: The maximum length is `32` characters. The minimum length is `1` character. The value must match regular expression `/[a-z,A-Z,0-9,-]/`. - -## Attribute Reference - -After your resource is created, you can read values from the listed arguments and the following attributes. - -* `id` - The unique identifier of the logs_router_tenant. -* `account_id` - (String) The account ID the tenant belongs to. - * Constraints: The maximum length is `32` characters. The minimum length is `32` characters. The value must match regular expression `/[a-z,A-Z,0-9,-]/`. -* `created_at` - (String) Time stamp the tenant was originally created. - * Constraints: The maximum length is `36` characters. The minimum length is `1` character. The value must match regular expression `/[0-9,:,.,-,T,Z]/`. -* `updated_at` - (String) time stamp the tenant was last updated. - * Constraints: The maximum length is `36` characters. The minimum length is `1` character. The value must match regular expression `/[0-9,:,.,-,T,Z]/`. - -## Import - -You can import the `ibm_logs_router_tenant` resource by using `id`. Unique ID of the created instance. - -# Syntax -
-$ terraform import ibm_logs_router_tenant.logs_router_tenant <id>
-
- -# Example -``` -$ terraform import ibm_logs_router_tenant.logs_router_tenant aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa -``` From add6e8c723fd81a594d2dd7449e4c97cff5d8f04 Mon Sep 17 00:00:00 2001 From: ismirlia <90468712+ismirlia@users.noreply.github.com> Date: Sun, 10 Dec 2023 20:51:14 -0600 Subject: [PATCH 05/14] Update pi_user_data to accept string input (#4974) * Add string support for pi_user_data field in instance creation * Add new user data test * Updated pi_user_data documentation * Remove duplicate import --- ibm/service/power/resource_ibm_pi_instance.go | 23 +++---- .../power/resource_ibm_pi_instance_test.go | 60 +++++++++++++++++++ website/docs/r/pi_instance.html.markdown | 2 +- 3 files changed, 68 insertions(+), 17 deletions(-) diff --git a/ibm/service/power/resource_ibm_pi_instance.go b/ibm/service/power/resource_ibm_pi_instance.go index 0a5a760803..610bf44813 100644 --- a/ibm/service/power/resource_ibm_pi_instance.go +++ b/ibm/service/power/resource_ibm_pi_instance.go @@ -856,12 +856,13 @@ func isPIInstanceRefreshFunc(client *st.IBMPIInstanceClient, id, instanceReadySt } } -func checkBase64(input string) error { - _, err := base64.StdEncoding.DecodeString(input) +// This function takes the input string and encodes into base64 if isn't already encoded +func encodeBase64(userData string) string { + _, err := base64.StdEncoding.DecodeString(userData) if err != nil { - return fmt.Errorf("failed to check if input is base64 %s", err) + return base64.StdEncoding.EncodeToString([]byte(userData)) } - return err + return userData } func isWaitForPIInstanceStopped(ctx context.Context, client *st.IBMPIInstanceClient, id string) (interface{}, error) { @@ -1081,12 +1082,7 @@ func createSAPInstance(d *schema.ResourceData, sapClient *st.IBMPISAPInstanceCli } if u, ok := d.GetOk(helpers.PIInstanceUserData); ok { userData := u.(string) - err := checkBase64(userData) - if err != nil { - log.Printf("Data is not base64 encoded") - return nil, err - } - body.UserData = userData + body.UserData = encodeBase64(userData) } if sys, ok := d.GetOk(helpers.PIInstanceSystemType); ok { body.SysType = sys.(string) @@ -1205,11 +1201,6 @@ func createPVMInstance(d *schema.ResourceData, client *st.IBMPIInstanceClient, i if u, ok := d.GetOk(helpers.PIInstanceUserData); ok { userData = u.(string) } - err := checkBase64(userData) - if err != nil { - log.Printf("Data is not base64 encoded") - return nil, err - } //publicinterface := d.Get(helpers.PIInstancePublicNetwork).(bool) body := &models.PVMInstanceCreate{ @@ -1221,7 +1212,7 @@ func createPVMInstance(d *schema.ResourceData, client *st.IBMPIInstanceClient, i ImageID: flex.PtrToString(imageid), ProcType: flex.PtrToString(processortype), Replicants: replicants, - UserData: userData, + UserData: encodeBase64(userData), ReplicantNamingScheme: flex.PtrToString(replicationNamingScheme), ReplicantAffinityPolicy: flex.PtrToString(replicationpolicy), Networks: pvmNetworks, diff --git a/ibm/service/power/resource_ibm_pi_instance_test.go b/ibm/service/power/resource_ibm_pi_instance_test.go index f6dbf5fba2..9e5555fadd 100644 --- a/ibm/service/power/resource_ibm_pi_instance_test.go +++ b/ibm/service/power/resource_ibm_pi_instance_test.go @@ -62,6 +62,47 @@ func testAccCheckIBMPIInstanceConfig(name, instanceHealthStatus string) string { `, acc.Pi_cloud_instance_id, name, acc.Pi_image, acc.Pi_network_name, instanceHealthStatus) } +func testAccCheckIBMPIInstanceUserDataConfig(name, instanceHealthStatus string) string { + return fmt.Sprintf(` + resource "ibm_pi_key" "key" { + pi_cloud_instance_id = "%[1]s" + pi_key_name = "%[2]s" + pi_ssh_key = "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEArb2aK0mekAdbYdY9rwcmeNSxqVCwez3WZTYEq+1Nwju0x5/vQFPSD2Kp9LpKBbxx3OVLN4VffgGUJznz9DAr7veLkWaf3iwEil6U4rdrhBo32TuDtoBwiczkZ9gn1uJzfIaCJAJdnO80Kv9k0smbQFq5CSb9H+F5VGyFue/iVd5/b30MLYFAz6Jg1GGWgw8yzA4Gq+nO7HtyuA2FnvXdNA3yK/NmrTiPCdJAtEPZkGu9LcelkQ8y90ArlKfjtfzGzYDE4WhOufFxyWxciUePh425J2eZvElnXSdGha+FCfYjQcvqpCVoBAG70U4fJBGjB+HL/GpCXLyiYXPrSnzC9w==" + } + data "ibm_pi_image" "power_image" { + pi_image_name = "%[3]s" + pi_cloud_instance_id = "%[1]s" + } + data "ibm_pi_network" "power_networks" { + pi_cloud_instance_id = "%[1]s" + pi_network_name = "%[4]s" + } + resource "ibm_pi_volume" "power_volume" { + pi_volume_size = 20 + pi_volume_name = "%[2]s" + pi_volume_shareable = true + pi_volume_pool = data.ibm_pi_image.power_image.storage_pool + pi_cloud_instance_id = "%[1]s" + } + resource "ibm_pi_instance" "power_instance" { + pi_memory = "2" + pi_processors = "0.25" + pi_instance_name = "%[2]s" + pi_proc_type = "shared" + pi_image_id = data.ibm_pi_image.power_image.id + pi_sys_type = "s922" + pi_cloud_instance_id = "%[1]s" + pi_storage_pool = data.ibm_pi_image.power_image.storage_pool + pi_health_status = "%[5]s" + pi_volume_ids = [ibm_pi_volume.power_volume.volume_id] + pi_network { + network_id = data.ibm_pi_network.power_networks.id + } + pi_user_data = "this is test user data" + } + `, acc.Pi_cloud_instance_id, name, acc.Pi_image, acc.Pi_network_name, instanceHealthStatus) +} + func testAccCheckIBMPIInstanceDeploymentTypeConfig(name, instanceHealthStatus string) string { return fmt.Sprintf(` resource "ibm_pi_key" "key" { @@ -238,6 +279,25 @@ func TestAccIBMPIInstanceBasic(t *testing.T) { }) } +func TestAccIBMPIInstanceUserData(t *testing.T) { + instanceRes := "ibm_pi_instance.power_instance" + name := fmt.Sprintf("tf-pi-instance-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPIInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIInstanceUserDataConfig(name, helpers.PIInstanceHealthWarning), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPIInstanceExists(instanceRes), + resource.TestCheckResourceAttr(instanceRes, "pi_instance_name", name), + ), + }, + }, + }) +} + func TestAccIBMPIInstanceDeploymentType(t *testing.T) { instanceRes := "ibm_pi_instance.power_instance" name := fmt.Sprintf("tf-pi-instance-%d", acctest.RandIntRange(10, 100)) diff --git a/website/docs/r/pi_instance.html.markdown b/website/docs/r/pi_instance.html.markdown index 6a5e2234a9..1001d49f34 100644 --- a/website/docs/r/pi_instance.html.markdown +++ b/website/docs/r/pi_instance.html.markdown @@ -99,7 +99,7 @@ Review the argument references that you can specify for your resource. - `pi_storage_connection` - (Optional, String) - Storage Connectivity Group (SCG) for server deployment. Only supported value is `vSCSI`. - `pi_sys_type` - (Optional, String) The type of system on which to create the VM (s922/e880/e980/s1022). - Supported SAP system types are (e880/e980). -- `pi_user_data` - (Optional, String) The base64 encoded form of the user data `cloud-init` to pass to the instance during creation. +- `pi_user_data` - (Optional, String) The user data `cloud-init` to pass to the instance during creation. It can be a base64 encoded or an unencoded string. If it is an unencoded string, the provider will encode it before it passing it down. - `pi_virtual_cores_assigned` - (Optional, Integer) Specify the number of virtual cores to be assigned. - `pi_volume_ids` - (Optional, List of String) The list of volume IDs that you want to attach to the instance during creation. ## Attribute reference From d05f916950f1bb9d102b30e896a97d975e1a1af8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Dec 2023 21:34:30 +0000 Subject: [PATCH 06/14] dependabot: bump actions/setup-go from 4 to 5 Bumps [actions/setup-go](https://github.com/actions/setup-go) from 4 to 5. - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/setup-go dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/go.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 7cb93f42ef..2fd6abc9a2 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -14,7 +14,7 @@ jobs: steps: - name: Set up Go 1.x - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: ^1.18 id: go diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d727809c5a..15f3a980ec 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: run: git fetch --prune --unshallow - name: Set up Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: 1.18 - From d7a06110981f4f53d22cb215d9faef31d06afe74 Mon Sep 17 00:00:00 2001 From: Justin Kanz Date: Mon, 11 Dec 2023 12:02:43 -0500 Subject: [PATCH 07/14] new host link endpoint commits (#4970) * new host link endpoint commits * add host link agent argument and example. Fixed RHEL7 repos to RHEL8 --------- Co-authored-by: Justin Kanz --- go.mod | 2 +- go.sum | 2 ++ .../data_source_ibm_satellite_host_script.go | 11 ++++++++++ ...a_source_ibm_satellite_host_script_test.go | 2 ++ ...satellite_attach_host_script.html.markdown | 22 ++++++++++--------- 5 files changed, 28 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index 4c06cd1d1d..55322cd7a7 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( github.com/IBM-Cloud/bluemix-go v0.0.0-20231204080125-462fa9e436bc - github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20231106114255-c50117860a3c + github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20231116055201-2a84da7b9bd6 github.com/IBM-Cloud/power-go-client v1.5.4 github.com/IBM/apigateway-go-sdk v0.0.0-20210714141226-a5d5d49caaca github.com/IBM/appconfiguration-go-admin-sdk v0.3.0 diff --git a/go.sum b/go.sum index e9de9e3543..30e5ffdf8e 100644 --- a/go.sum +++ b/go.sum @@ -104,6 +104,8 @@ github.com/IBM-Cloud/bluemix-go v0.0.0-20231204080125-462fa9e436bc h1:AeooCa6UMW github.com/IBM-Cloud/bluemix-go v0.0.0-20231204080125-462fa9e436bc/go.mod h1:jIGLnIfj+uBv2ALz3rVHzNbNwt0V/bEWNeJKECa8Q+k= github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20231106114255-c50117860a3c h1:tRS4VuOG3lHNG+yrsh3vZZQDVNLuFJB0oZbTJp9YXds= github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20231106114255-c50117860a3c/go.mod h1:xUQL9SGAjoZFd4GNjrjjtEpjpkgU7RFXRyHesbKTjiY= +github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20231116055201-2a84da7b9bd6 h1:QXU1Atl/JSI3ZtYB9tHbWLhrFYE1E+5Iww1sjQ7mqdo= +github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20231116055201-2a84da7b9bd6/go.mod h1:xUQL9SGAjoZFd4GNjrjjtEpjpkgU7RFXRyHesbKTjiY= github.com/IBM-Cloud/ibm-cloud-cli-sdk v0.5.3/go.mod h1:RiUvKuHKTBmBApDMUQzBL14pQUGKcx/IioKQPIcRQjs= github.com/IBM-Cloud/power-go-client v1.5.4 h1:fk+QgOdZvwq696UynehfGrMGMHXDYOJfRCE3Pec9o6c= github.com/IBM-Cloud/power-go-client v1.5.4/go.mod h1:ZsKqKC4d4MAWujkttW1w9tG7xjlIbkIpVENX476ghVY= diff --git a/ibm/service/satellite/data_source_ibm_satellite_host_script.go b/ibm/service/satellite/data_source_ibm_satellite_host_script.go index 069f1f60e5..48ac821502 100644 --- a/ibm/service/satellite/data_source_ibm_satellite_host_script.go +++ b/ibm/service/satellite/data_source_ibm_satellite_host_script.go @@ -74,6 +74,11 @@ func DataSourceIBMSatelliteAttachHostScript() *schema.Resource { Optional: true, ExactlyOneOf: []string{"host_provider", "custom_script"}, }, + "host_link_agent_endpoint": { + Description: "The satellite link agent endpoint, required for reduced firewall attach script", + Type: schema.TypeString, + Optional: true, + }, }, } } @@ -155,6 +160,12 @@ func dataSourceIBMSatelliteAttachHostScriptRead(d *schema.ResourceData, meta int scriptPath = filepath.Join(scriptDir, "addHost.sh") } + // If the user supplied link agent endpoint, use reduced firewall attach script + if hlae, ok := d.GetOk("host_link_agent_endpoint"); ok { + host_link_agent_endpoint := hlae.(string) + createRegOptions.HostLinkAgentEndpoint = &host_link_agent_endpoint + } + resp, err := satClient.AttachSatelliteHost(createRegOptions) if err != nil { return fmt.Errorf("[ERROR] Error Generating Satellite Registration Script: %s\n%s", err, resp) diff --git a/ibm/service/satellite/data_source_ibm_satellite_host_script_test.go b/ibm/service/satellite/data_source_ibm_satellite_host_script_test.go index 6d3a98709f..9c09d5a5a8 100644 --- a/ibm/service/satellite/data_source_ibm_satellite_host_script_test.go +++ b/ibm/service/satellite/data_source_ibm_satellite_host_script_test.go @@ -55,6 +55,7 @@ func TestAccIBMSatelliteAttachHostScriptDataSourceBasicCoreos(t *testing.T) { Config: testAccCheckIBMSatelliteAttachHostScriptDataSourceConfigCoreos(locationName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.ibm_satellite_attach_host_script.script", "host_provider", "ibm"), + resource.TestCheckResourceAttr("data.ibm_satellite_attach_host_script.script", "host_link_agent_endpoint", "testendpoint"), ), }, }, @@ -75,5 +76,6 @@ data "ibm_satellite_attach_host_script" "script" { labels = ["env:prod"] coreos_host = true host_provider = "ibm" + host_link_agent_endpoint = "testendpoint" }`, locationName) } diff --git a/website/docs/d/satellite_attach_host_script.html.markdown b/website/docs/d/satellite_attach_host_script.html.markdown index 824f177ec9..e578670ec5 100644 --- a/website/docs/d/satellite_attach_host_script.html.markdown +++ b/website/docs/d/satellite_attach_host_script.html.markdown @@ -21,14 +21,15 @@ data "ibm_satellite_attach_host_script" "script" { } ``` -### Sample to read satellite host script to attach AWS EC2 host to Satellite control plane +### Sample to read satellite host script to attach AWS EC2 host to Satellite control plane and uses reduced firewall requirements. ```terraform data "ibm_satellite_attach_host_script" "script" { - location = var.location - labels = var.labels - script_dir = "/tmp" - host_provider = "aws" + location = var.location + labels = var.labels + script_dir = "/tmp" + host_provider = "aws" + host_link_agent_endpoint = "c-01-ws.us-south.link.satellite.cloud.ibm.com" } ``` ### Sample to read satellite host script to attach IBM host to Satellite control plane @@ -38,11 +39,11 @@ data "ibm_satellite_attach_host_script" "script" { location = var.location custom_script = < Date: Tue, 12 Dec 2023 10:29:47 -0600 Subject: [PATCH 08/14] Add mtu and accessConfig flags to subnet create commands for terraform (#4690) * Add mtu and accessConfig flags to subnet create commands for terraform * Fix terraform compile errors * Fix terraform compile error from yaml changes * Clean up warnings in powervs provider * Fix bug checking region instead of zone for satellite check * Hide shared processor pool and IBMi license arguments from being set in satellite location * Fix typing issues in MTU and access config Three issues here: - There is no schema.TypeInt64, so I have to set this field to schema.TypeInt. Pretend this value is an int and then cast it back to an int64. This an issue with the terraform sdk. - I accidentally set schema.Int on access config where it should be schema.TypeString - All passed in variables by the user need to be set or else the sdk and/or service broker can't safeguard against bad values correctly * Update new network field satellite documentation * Revert nullable name change Due to incompatibility between to the two service brokers, this change has to be undone to maintain consistency. * Update go mod files for new sdk version * Add satellite network acceptance test * Update mtu and jumbo descriptions * Add access-config validation to terraform --- .../data_source_ibm_pi_catalog_images.go | 14 +++--- .../power/data_source_ibm_pi_instance.go | 4 -- .../power/data_source_ibm_pi_network.go | 12 ++++- ibm/service/power/resource_ibm_pi_network.go | 33 ++++++++++-- .../power/resource_ibm_pi_network_port.go | 2 +- .../power/resource_ibm_pi_network_test.go | 50 +++++++++++++++++++ website/docs/d/pi_network.html.markdown | 4 +- website/docs/r/pi_network.html.markdown | 4 +- 8 files changed, 103 insertions(+), 20 deletions(-) diff --git a/ibm/service/power/data_source_ibm_pi_catalog_images.go b/ibm/service/power/data_source_ibm_pi_catalog_images.go index eb505ac070..62adf75a8e 100644 --- a/ibm/service/power/data_source_ibm_pi_catalog_images.go +++ b/ibm/service/power/data_source_ibm_pi_catalog_images.go @@ -163,25 +163,25 @@ func dataSourceIBMPICatalogImagesRead(ctx context.Context, d *schema.ResourceDat } if i.Specifications != nil { s := i.Specifications - if &s.ImageType != nil { + if s.ImageType != "" { image["image_type"] = s.ImageType } - if &s.ContainerFormat != nil { + if s.ContainerFormat != "" { image["container_format"] = s.ContainerFormat } - if &s.DiskFormat != nil { + if s.DiskFormat != "" { image["disk_format"] = s.DiskFormat } - if &s.OperatingSystem != nil { + if s.OperatingSystem != "" { image["operating_system"] = s.OperatingSystem } - if &s.HypervisorType != nil { + if s.HypervisorType != "" { image["hypervisor_type"] = s.HypervisorType } - if &s.Architecture != nil { + if s.Architecture != "" { image["architecture"] = s.Architecture } - if &s.Endianness != nil { + if s.Endianness != "" { image["endianness"] = s.Endianness } } diff --git a/ibm/service/power/data_source_ibm_pi_instance.go b/ibm/service/power/data_source_ibm_pi_instance.go index f6dd4d2d9b..354cfe951b 100644 --- a/ibm/service/power/data_source_ibm_pi_instance.go +++ b/ibm/service/power/data_source_ibm_pi_instance.go @@ -246,7 +246,6 @@ func dataSourceIBMPIInstancesRead(ctx context.Context, d *schema.ResourceData, m if powervmdata.Addresses != nil { pvmaddress := make([]map[string]interface{}, len(powervmdata.Addresses)) for i, pvmip := range powervmdata.Addresses { - p := make(map[string]interface{}) p["ip"] = pvmip.IPAddress p["network_name"] = pvmip.NetworkName @@ -257,13 +256,10 @@ func dataSourceIBMPIInstancesRead(ctx context.Context, d *schema.ResourceData, m pvmaddress[i] = p } d.Set("addresses", pvmaddress) - } if powervmdata.Health != nil { - d.Set("health_status", powervmdata.Health.Status) - } return nil diff --git a/ibm/service/power/data_source_ibm_pi_network.go b/ibm/service/power/data_source_ibm_pi_network.go index a080f5a022..3a04453ca7 100644 --- a/ibm/service/power/data_source_ibm_pi_network.go +++ b/ibm/service/power/data_source_ibm_pi_network.go @@ -39,12 +39,10 @@ func DataSourceIBMPINetwork() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "type": { Type: schema.TypeString, Computed: true, }, - "vlan_id": { Type: schema.TypeInt, Computed: true, @@ -79,6 +77,14 @@ func DataSourceIBMPINetwork() *schema.Resource { Type: schema.TypeBool, Computed: true, }, + "mtu": { + Type: schema.TypeInt, + Computed: true, + }, + "access_config": { + Type: schema.TypeString, + Computed: true, + }, }, } } @@ -124,6 +130,8 @@ func dataSourceIBMPINetworkRead(ctx context.Context, d *schema.ResourceData, met d.Set("dns", networkdata.DNSServers) } d.Set("jumbo", networkdata.Jumbo) + d.Set("mtu", networkdata.Mtu) + d.Set("access_config", networkdata.AccessConfig) return nil diff --git a/ibm/service/power/resource_ibm_pi_network.go b/ibm/service/power/resource_ibm_pi_network.go index 113e5f9176..49e85d9aa5 100644 --- a/ibm/service/power/resource_ibm_pi_network.go +++ b/ibm/service/power/resource_ibm_pi_network.go @@ -75,10 +75,26 @@ func ResourceIBMPINetwork() *schema.Resource { Description: "PI network gateway", }, helpers.PINetworkJumbo: { - Type: schema.TypeBool, - Optional: true, - Computed: true, - Description: "PI network enable MTU Jumbo option", + Type: schema.TypeBool, + Optional: true, + Computed: true, + Deprecated: "deprecated use pi_network_mtu instead", + ExactlyOneOf: []string{helpers.PINetworkMtu, helpers.PINetworkJumbo}, + Description: "PI network enable MTU Jumbo option", + }, + helpers.PINetworkMtu: { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ExactlyOneOf: []string{helpers.PINetworkMtu, helpers.PINetworkJumbo}, + Description: "PI Maximum Transmission Unit", + }, + helpers.PINetworkAccessConfig: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.ValidateAllowedStringValues([]string{"internal-only", "outbound-only", "bidirectional-static-route", "bidirectional-bgp", "bidirectional-l2out"}), + Description: "PI network communication configuration", }, helpers.PICloudInstanceId: { Type: schema.TypeString, @@ -145,6 +161,13 @@ func resourceIBMPINetworkCreate(ctx context.Context, d *schema.ResourceData, met if v, ok := d.GetOk(helpers.PINetworkJumbo); ok { body.Jumbo = v.(bool) } + if v, ok := d.GetOk(helpers.PINetworkMtu); ok { + var mtu int64 = int64(v.(int)) + body.Mtu = &mtu + } + if v, ok := d.GetOk(helpers.PINetworkAccessConfig); ok { + body.AccessConfig = models.AccessConfig(v.(string)) + } if networktype == "vlan" { var networkcidr string @@ -216,6 +239,8 @@ func resourceIBMPINetworkRead(ctx context.Context, d *schema.ResourceData, meta d.Set(helpers.PINetworkName, networkdata.Name) d.Set(helpers.PINetworkType, networkdata.Type) d.Set(helpers.PINetworkJumbo, networkdata.Jumbo) + d.Set(helpers.PINetworkMtu, networkdata.Mtu) + d.Set(helpers.PINetworkAccessConfig, networkdata.AccessConfig) d.Set(helpers.PINetworkGateway, networkdata.Gateway) ipRangesMap := []map[string]interface{}{} if networkdata.IPAddressRanges != nil { diff --git a/ibm/service/power/resource_ibm_pi_network_port.go b/ibm/service/power/resource_ibm_pi_network_port.go index 703686eb0b..6b1ffb0cf7 100644 --- a/ibm/service/power/resource_ibm_pi_network_port.go +++ b/ibm/service/power/resource_ibm_pi_network_port.go @@ -200,7 +200,7 @@ func isIBMPINetworkPortRefreshFunc(client *st.IBMPINetworkClient, id, networknam return nil, "", err } - if &network.PortID != nil { + if network.PortID != nil { //if network.State == "available" { log.Printf(" The port has been created with the following ip address and attached to an instance ") return network, "DOWN", nil diff --git a/ibm/service/power/resource_ibm_pi_network_test.go b/ibm/service/power/resource_ibm_pi_network_test.go index 517bf87118..249ce65615 100644 --- a/ibm/service/power/resource_ibm_pi_network_test.go +++ b/ibm/service/power/resource_ibm_pi_network_test.go @@ -88,6 +88,43 @@ func TestAccIBMPINetworkGatewaybasic(t *testing.T) { }, }) } + +func TestAccIBMPINetworkGatewaybasicSatellite(t *testing.T) { + name := fmt.Sprintf("tf-pi-network-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPINetworkDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPINetworkGatewayConfigSatellite(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPINetworkExists("ibm_pi_network.power_networks"), + resource.TestCheckResourceAttr( + "ibm_pi_network.power_networks", "pi_network_name", name), + resource.TestCheckResourceAttrSet("ibm_pi_network.power_networks", "pi_gateway"), + resource.TestCheckResourceAttrSet("ibm_pi_network.power_networks", "id"), + resource.TestCheckResourceAttrSet("ibm_pi_network.power_networks", "pi_ipaddress_range.#"), + ), + }, + { + Config: testAccCheckIBMPINetworkConfigGatewayUpdateDNS(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPINetworkExists("ibm_pi_network.power_networks"), + resource.TestCheckResourceAttr( + "ibm_pi_network.power_networks", "pi_network_name", name), + resource.TestCheckResourceAttr( + "ibm_pi_network.power_networks", "pi_gateway", "192.168.17.2"), + resource.TestCheckResourceAttr( + "ibm_pi_network.power_networks", "pi_ipaddress_range.0.pi_ending_ip_address", "192.168.17.254"), + resource.TestCheckResourceAttr( + "ibm_pi_network.power_networks", "pi_ipaddress_range.0.pi_starting_ip_address", "192.168.17.3"), + ), + }, + }, + }) +} + func testAccCheckIBMPINetworkDestroy(s *terraform.State) error { sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() @@ -190,3 +227,16 @@ func testAccCheckIBMPINetworkConfigGatewayUpdateDNS(name string) string { } `, acc.Pi_cloud_instance_id, name) } + +func testAccCheckIBMPINetworkGatewayConfigSatellite(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_network" "power_networks" { + pi_cloud_instance_id = "%s" + pi_network_name = "%s" + pi_network_type = "vlan" + pi_cidr = "192.168.17.0/24" + pi_network_mtu = 6500 + pi_network_access_config = "outbound-only" + } + `, acc.Pi_cloud_instance_id, name) +} diff --git a/website/docs/d/pi_network.html.markdown b/website/docs/d/pi_network.html.markdown index eea249a557..c4f03cb824 100644 --- a/website/docs/d/pi_network.html.markdown +++ b/website/docs/d/pi_network.html.markdown @@ -53,4 +53,6 @@ In addition to all argument reference list, you can access the following attribu - `used_ip_count` - (Float) The number of used IP addresses. - `used_ip_percent` - (Float) The percentage of IP addresses used. - `vlan_id` - (String) The VLAN ID that the network is connected to. -- `jumbo` - (Bool) MTU Jumbo option of the network. +- `jumbo` - (Bool) MTU Jumbo option of the network (for multi-zone locations only). `deprecated` +- `mtu` - (Bool) Maximum Transmission Unit option of the network. +- `access_config` - (String) The network communication configuration option of the network (for satellite locations only). \ No newline at end of file diff --git a/website/docs/r/pi_network.html.markdown b/website/docs/r/pi_network.html.markdown index 23da3c3de9..4abefe7694 100644 --- a/website/docs/r/pi_network.html.markdown +++ b/website/docs/r/pi_network.html.markdown @@ -69,7 +69,9 @@ Review the argument references that you can specify for your resource. The `pi_ipaddress_range` block supports: - `pi_ending_ip_address` - (Required, String) The ending ip address. - `pi_starting_ip_address` - (Required, String) The staring ip address. **Note** if the `pi_gateway` or `pi_ipaddress_range` is not provided, it will calculate the value based on CIDR respectively. -- `pi_network_jumbo` - (Optional, Bool) MTU Jumbo option of the network. +- `pi_network_jumbo` - (Optional, Bool) MTU Jumbo option of the network (for multi-zone locations only). `deprecated` use `pi_network_mtu` instead. +- `pi_network_mtu` - (Optional, Integer) Maximum Transmission Unit option of the network, min size = 1450 & max size = 9000. +- `pi_network_access_config` - (Optional, String) The network communication configuration option of the network (for satellite locations only). ## Attribute reference From 6aa6b14b7ad290306f3aec04adf8442341dee8a0 Mon Sep 17 00:00:00 2001 From: Shuaib Bapputty Date: Tue, 12 Dec 2023 12:08:16 +0530 Subject: [PATCH 09/14] feat: add new service mqcloud --- examples/ibm-mqcloud/README.md | 175 ++++++++ examples/ibm-mqcloud/main.tf | 103 +++++ examples/ibm-mqcloud/outputs.tf | 30 ++ examples/ibm-mqcloud/variables.tf | 203 +++++++++ examples/ibm-mqcloud/versions.tf | 9 + go.mod | 48 +- go.sum | 160 +++---- ibm/acctest/acctest.go | 42 ++ ibm/conns/config.go | 40 ++ ibm/provider/provider.go | 23 + ibm/service/mqcloud/README.md | 11 + .../data_source_ibm_mqcloud_application.go | 167 +++++++ ...ata_source_ibm_mqcloud_application_test.go | 87 ++++ ...source_ibm_mqcloud_keystore_certificate.go | 223 ++++++++++ ...e_ibm_mqcloud_keystore_certificate_test.go | 107 +++++ .../data_source_ibm_mqcloud_queue_manager.go | 232 ++++++++++ ...source_ibm_mqcloud_queue_manager_status.go | 77 ++++ ...e_ibm_mqcloud_queue_manager_status_test.go | 44 ++ ...a_source_ibm_mqcloud_queue_manager_test.go | 114 +++++ ...urce_ibm_mqcloud_truststore_certificate.go | 208 +++++++++ ...ibm_mqcloud_truststore_certificate_test.go | 106 +++++ .../mqcloud/data_source_ibm_mqcloud_user.go | 166 +++++++ .../data_source_ibm_mqcloud_user_test.go | 93 ++++ .../resource_ibm_mqcloud_application.go | 188 ++++++++ .../resource_ibm_mqcloud_application_test.go | 150 +++++++ ...source_ibm_mqcloud_keystore_certificate.go | 314 +++++++++++++ ...e_ibm_mqcloud_keystore_certificate_test.go | 163 +++++++ .../resource_ibm_mqcloud_queue_manager.go | 415 ++++++++++++++++++ ...resource_ibm_mqcloud_queue_manager_test.go | 182 ++++++++ ...urce_ibm_mqcloud_truststore_certificate.go | 297 +++++++++++++ ...ibm_mqcloud_truststore_certificate_test.go | 163 +++++++ .../mqcloud/resource_ibm_mqcloud_user.go | 196 +++++++++ .../mqcloud/resource_ibm_mqcloud_user_test.go | 157 +++++++ ibm/service/mqcloud/utils.go | 196 +++++++++ website/allowed-subcategories.txt | 1 + .../docs/d/mqcloud_application.html.markdown | 44 ++ ...mqcloud_keystore_certificate.html.markdown | 63 +++ .../d/mqcloud_queue_manager.html.markdown | 60 +++ ...mqcloud_queue_manager_status.html.markdown | 38 ++ ...cloud_truststore_certificate.html.markdown | 60 +++ website/docs/d/mqcloud_user.html.markdown | 46 ++ .../guides/custom-service-endpoints.html.md | 13 +- .../docs/r/mqcloud_application.html.markdown | 55 +++ ...mqcloud_keystore_certificate.html.markdown | 73 +++ .../r/mqcloud_queue_manager.html.markdown | 74 ++++ ...cloud_truststore_certificate.html.markdown | 70 +++ website/docs/r/mqcloud_user.html.markdown | 57 +++ 47 files changed, 5426 insertions(+), 117 deletions(-) create mode 100644 examples/ibm-mqcloud/README.md create mode 100644 examples/ibm-mqcloud/main.tf create mode 100644 examples/ibm-mqcloud/outputs.tf create mode 100644 examples/ibm-mqcloud/variables.tf create mode 100644 examples/ibm-mqcloud/versions.tf create mode 100644 ibm/service/mqcloud/README.md create mode 100644 ibm/service/mqcloud/data_source_ibm_mqcloud_application.go create mode 100644 ibm/service/mqcloud/data_source_ibm_mqcloud_application_test.go create mode 100644 ibm/service/mqcloud/data_source_ibm_mqcloud_keystore_certificate.go create mode 100644 ibm/service/mqcloud/data_source_ibm_mqcloud_keystore_certificate_test.go create mode 100644 ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager.go create mode 100644 ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_status.go create mode 100644 ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_status_test.go create mode 100644 ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_test.go create mode 100644 ibm/service/mqcloud/data_source_ibm_mqcloud_truststore_certificate.go create mode 100644 ibm/service/mqcloud/data_source_ibm_mqcloud_truststore_certificate_test.go create mode 100644 ibm/service/mqcloud/data_source_ibm_mqcloud_user.go create mode 100644 ibm/service/mqcloud/data_source_ibm_mqcloud_user_test.go create mode 100644 ibm/service/mqcloud/resource_ibm_mqcloud_application.go create mode 100644 ibm/service/mqcloud/resource_ibm_mqcloud_application_test.go create mode 100644 ibm/service/mqcloud/resource_ibm_mqcloud_keystore_certificate.go create mode 100644 ibm/service/mqcloud/resource_ibm_mqcloud_keystore_certificate_test.go create mode 100644 ibm/service/mqcloud/resource_ibm_mqcloud_queue_manager.go create mode 100644 ibm/service/mqcloud/resource_ibm_mqcloud_queue_manager_test.go create mode 100644 ibm/service/mqcloud/resource_ibm_mqcloud_truststore_certificate.go create mode 100644 ibm/service/mqcloud/resource_ibm_mqcloud_truststore_certificate_test.go create mode 100644 ibm/service/mqcloud/resource_ibm_mqcloud_user.go create mode 100644 ibm/service/mqcloud/resource_ibm_mqcloud_user_test.go create mode 100644 ibm/service/mqcloud/utils.go create mode 100644 website/docs/d/mqcloud_application.html.markdown create mode 100644 website/docs/d/mqcloud_keystore_certificate.html.markdown create mode 100644 website/docs/d/mqcloud_queue_manager.html.markdown create mode 100644 website/docs/d/mqcloud_queue_manager_status.html.markdown create mode 100644 website/docs/d/mqcloud_truststore_certificate.html.markdown create mode 100644 website/docs/d/mqcloud_user.html.markdown create mode 100644 website/docs/r/mqcloud_application.html.markdown create mode 100644 website/docs/r/mqcloud_keystore_certificate.html.markdown create mode 100644 website/docs/r/mqcloud_queue_manager.html.markdown create mode 100644 website/docs/r/mqcloud_truststore_certificate.html.markdown create mode 100644 website/docs/r/mqcloud_user.html.markdown diff --git a/examples/ibm-mqcloud/README.md b/examples/ibm-mqcloud/README.md new file mode 100644 index 0000000000..ae8ef2a8dd --- /dev/null +++ b/examples/ibm-mqcloud/README.md @@ -0,0 +1,175 @@ +# Example for MqcloudV1 + +This example illustrates how to use the MqcloudV1 + +The following types of resources are supported: + +* mqcloud_queue_manager +* mqcloud_application +* mqcloud_user +* mqcloud_keystore_certificate +* mqcloud_truststore_certificate + +## Usage + +To run this example, execute the following commands: + +```bash +$ terraform init +$ terraform plan +$ terraform apply +``` + +Run `terraform destroy` when you don't need these resources. + + +## MqcloudV1 resources + +mqcloud_queue_manager resource: + +```hcl +resource "mqcloud_queue_manager" "mqcloud_queue_manager_instance" { + service_instance_guid = var.mqcloud_queue_manager_service_instance_guid + name = var.mqcloud_queue_manager_name + display_name = var.mqcloud_queue_manager_display_name + location = var.mqcloud_queue_manager_location + size = var.mqcloud_queue_manager_size + version = var.mqcloud_queue_manager_version +} +``` +mqcloud_application resource: + +```hcl +resource "mqcloud_application" "mqcloud_application_instance" { + service_instance_guid = var.mqcloud_application_service_instance_guid + name = var.mqcloud_application_name +} +``` +mqcloud_user resource: + +```hcl +resource "mqcloud_user" "mqcloud_user_instance" { + service_instance_guid = var.mqcloud_user_service_instance_guid + name = var.mqcloud_user_name + email = var.mqcloud_user_email +} +``` +mqcloud_keystore_certificate resource: + +```hcl +resource "mqcloud_keystore_certificate" "mqcloud_keystore_certificate_instance" { + service_instance_guid = var.mqcloud_keystore_certificate_service_instance_guid + queue_manager_id = var.mqcloud_keystore_certificate_queue_manager_id + label = var.mqcloud_keystore_certificate_label +} +``` +mqcloud_truststore_certificate resource: + +```hcl +resource "mqcloud_truststore_certificate" "mqcloud_truststore_certificate_instance" { + service_instance_guid = var.mqcloud_truststore_certificate_service_instance_guid + queue_manager_id = var.mqcloud_truststore_certificate_queue_manager_id + label = var.mqcloud_truststore_certificate_label +} +``` + +## MqcloudV1 data sources + +mqcloud_queue_manager data source: + +```hcl +data "mqcloud_queue_manager" "mqcloud_queue_manager_instance" { + service_instance_guid = var.mqcloud_queue_manager_service_instance_guid + name = var.mqcloud_queue_manager_name +} +``` +mqcloud_queue_manager_status data source: + +```hcl +data "mqcloud_queue_manager_status" "mqcloud_queue_manager_status_instance" { + service_instance_guid = var.mqcloud_queue_manager_status_service_instance_guid + queue_manager_id = var.mqcloud_queue_manager_status_queue_manager_id +} +``` +mqcloud_application data source: + +```hcl +data "mqcloud_application" "mqcloud_application_instance" { + service_instance_guid = var.mqcloud_application_service_instance_guid + name = var.mqcloud_application_name +} +``` +mqcloud_user data source: + +```hcl +data "mqcloud_user" "mqcloud_user_instance" { + service_instance_guid = var.mqcloud_user_service_instance_guid + name = var.mqcloud_user_name +} +``` +mqcloud_truststore_certificate data source: + +```hcl +data "mqcloud_truststore_certificate" "mqcloud_truststore_certificate_instance" { + service_instance_guid = var.mqcloud_truststore_certificate_service_instance_guid + queue_manager_id = var.mqcloud_truststore_certificate_queue_manager_id + label = var.mqcloud_truststore_certificate_label +} +``` +mqcloud_keystore_certificate data source: + +```hcl +data "mqcloud_keystore_certificate" "mqcloud_keystore_certificate_instance" { + service_instance_guid = var.mqcloud_keystore_certificate_service_instance_guid + queue_manager_id = var.mqcloud_keystore_certificate_queue_manager_id + label = var.mqcloud_keystore_certificate_label +} +``` + +## Assumptions + +1. TODO + +## Notes + +1. TODO + +## Requirements + +| Name | Version | +|------|---------| +| terraform | ~> 0.12 | + +## Providers + +| Name | Version | +|------|---------| +| ibm | 1.13.1 | + +## Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| ibmcloud\_api\_key | IBM Cloud API key | `string` | true | +| service_instance_guid | The GUID that uniquely identifies the MQ on Cloud service instance. | `string` | true | +| name | A queue manager name conforming to MQ restrictions. | `string` | true | +| display_name | A displayable name for the queue manager - limited only in length. | `string` | false | +| location | The locations in which the queue manager could be deployed. | `string` | true | +| size | The queue manager sizes of deployment available. Deployment of lite queue managers for aws_us_east_1 and aws_eu_west_1 locations is not available. | `string` | true | +| version | The MQ version of the queue manager. | `string` | false | +| name | The name of the application - conforming to MQ rules. | `string` | true | +| name | The shortname of the user that will be used as the IBM MQ administrator in interactions with a queue manager for this service instance. | `string` | true | +| email | The email of the user. | `string` | true | +| queue_manager_id | The id of the queue manager to retrieve its full details. | `string` | true | +| label | Certificate label in queue manager store. | `string` | true | + +## Outputs + +| Name | Description | +|------|-------------| +| mqcloud_queue_manager | mqcloud_queue_manager object | +| mqcloud_queue_manager_status | mqcloud_queue_manager_status object | +| mqcloud_application | mqcloud_application object | +| mqcloud_user | mqcloud_user object | +| mqcloud_truststore_certificate | mqcloud_truststore_certificate object | +| mqcloud_keystore_certificate | mqcloud_keystore_certificate object | diff --git a/examples/ibm-mqcloud/main.tf b/examples/ibm-mqcloud/main.tf new file mode 100644 index 0000000000..b89e08c72a --- /dev/null +++ b/examples/ibm-mqcloud/main.tf @@ -0,0 +1,103 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key +} + +// Provision mqcloud_queue_manager resource instance +resource "ibm_mqcloud_queue_manager" "mqcloud_queue_manager_instance" { + service_instance_guid = var.mqcloud_queue_manager_service_instance_guid + name = var.mqcloud_queue_manager_name + display_name = var.mqcloud_queue_manager_display_name + location = var.mqcloud_queue_manager_location + size = var.mqcloud_queue_manager_size + version = var.mqcloud_queue_manager_version +} + +// Provision mqcloud_application resource instance +resource "ibm_mqcloud_application" "mqcloud_application_instance" { + service_instance_guid = var.mqcloud_application_service_instance_guid + name = var.mqcloud_application_name +} + +// Provision mqcloud_user resource instance +resource "ibm_mqcloud_user" "mqcloud_user_instance" { + service_instance_guid = var.mqcloud_user_service_instance_guid + name = var.mqcloud_user_name + email = var.mqcloud_user_email +} + +// Provision mqcloud_keystore_certificate resource instance +resource "ibm_mqcloud_keystore_certificate" "mqcloud_keystore_certificate_instance" { + service_instance_guid = var.mqcloud_keystore_certificate_service_instance_guid + queue_manager_id = var.mqcloud_keystore_certificate_queue_manager_id + label = var.mqcloud_keystore_certificate_label +} + +// Provision mqcloud_truststore_certificate resource instance +resource "ibm_mqcloud_truststore_certificate" "mqcloud_truststore_certificate_instance" { + service_instance_guid = var.mqcloud_truststore_certificate_service_instance_guid + queue_manager_id = var.mqcloud_truststore_certificate_queue_manager_id + label = var.mqcloud_truststore_certificate_label +} + +// Data source is not linked to a resource instance +// Uncomment if an existing data source instance exists +/* +// Create mqcloud_queue_manager data source +data "ibm_mqcloud_queue_manager" "mqcloud_queue_manager_instance" { + service_instance_guid = var.mqcloud_queue_manager_service_instance_guid + + name = var.mqcloud_queue_manager_name +} +*/ + +// Data source is not linked to a resource instance +// Uncomment if an existing data source instance exists +/* +// Create mqcloud_queue_manager_status data source +data "ibm_mqcloud_queue_manager_status" "mqcloud_queue_manager_status_instance" { + service_instance_guid = var.mqcloud_queue_manager_status_service_instance_guid + queue_manager_id = var.mqcloud_queue_manager_status_queue_manager_id +} +*/ + +// Data source is not linked to a resource instance +// Uncomment if an existing data source instance exists +/* +// Create mqcloud_application data source +data "ibm_mqcloud_application" "mqcloud_application_instance" { + service_instance_guid = var.mqcloud_application_service_instance_guid + name = var.mqcloud_application_name +} +*/ + +// Data source is not linked to a resource instance +// Uncomment if an existing data source instance exists +/* +// Create mqcloud_user data source +data "ibm_mqcloud_user" "mqcloud_user_instance" { + service_instance_guid = var.mqcloud_user_service_instance_guid + name = var.mqcloud_user_name +} +*/ + +// Data source is not linked to a resource instance +// Uncomment if an existing data source instance exists +/* +// Create mqcloud_truststore_certificate data source +data "ibm_mqcloud_truststore_certificate" "mqcloud_truststore_certificate_instance" { + service_instance_guid = var.mqcloud_truststore_certificate_service_instance_guid + queue_manager_id = var.mqcloud_truststore_certificate_queue_manager_id + label = var.mqcloud_truststore_certificate_label +} +*/ + +// Data source is not linked to a resource instance +// Uncomment if an existing data source instance exists +/* +// Create mqcloud_keystore_certificate data source +data "ibm_mqcloud_keystore_certificate" "mqcloud_keystore_certificate_instance" { + service_instance_guid = var.mqcloud_keystore_certificate_service_instance_guid + queue_manager_id = var.mqcloud_keystore_certificate_queue_manager_id + label = var.mqcloud_keystore_certificate_label +} +*/ diff --git a/examples/ibm-mqcloud/outputs.tf b/examples/ibm-mqcloud/outputs.tf new file mode 100644 index 0000000000..ebd87da85e --- /dev/null +++ b/examples/ibm-mqcloud/outputs.tf @@ -0,0 +1,30 @@ +// This output allows mqcloud_queue_manager data to be referenced by other resources and the terraform CLI +// Modify this output if only certain data should be exposed +output "ibm_mqcloud_queue_manager" { + value = ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance + description = "mqcloud_queue_manager resource instance" +} +// This output allows mqcloud_application data to be referenced by other resources and the terraform CLI +// Modify this output if only certain data should be exposed +output "ibm_mqcloud_application" { + value = ibm_mqcloud_application.mqcloud_application_instance + description = "mqcloud_application resource instance" +} +// This output allows mqcloud_user data to be referenced by other resources and the terraform CLI +// Modify this output if only certain data should be exposed +output "ibm_mqcloud_user" { + value = ibm_mqcloud_user.mqcloud_user_instance + description = "mqcloud_user resource instance" +} +// This output allows mqcloud_keystore_certificate data to be referenced by other resources and the terraform CLI +// Modify this output if only certain data should be exposed +output "ibm_mqcloud_keystore_certificate" { + value = ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance + description = "mqcloud_keystore_certificate resource instance" +} +// This output allows mqcloud_truststore_certificate data to be referenced by other resources and the terraform CLI +// Modify this output if only certain data should be exposed +output "ibm_mqcloud_truststore_certificate" { + value = ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance + description = "mqcloud_truststore_certificate resource instance" +} diff --git a/examples/ibm-mqcloud/variables.tf b/examples/ibm-mqcloud/variables.tf new file mode 100644 index 0000000000..dba4d0fff0 --- /dev/null +++ b/examples/ibm-mqcloud/variables.tf @@ -0,0 +1,203 @@ +variable "ibmcloud_api_key" { + description = "IBM Cloud API key" + type = string +} + +// Resource arguments for mqcloud_queue_manager +variable "mqcloud_queue_manager_service_instance_guid" { + description = "The GUID that uniquely identifies the MQ on Cloud service instance." + type = string + default = "Service Instance ID" +} +variable "mqcloud_queue_manager_name" { + description = "A queue manager name conforming to MQ restrictions." + type = string + default = "testqm" +} +variable "mqcloud_queue_manager_display_name" { + description = "A displayable name for the queue manager - limited only in length." + type = string + default = "A test queue manager" +} +variable "mqcloud_queue_manager_location" { + description = "The locations in which the queue manager could be deployed." + type = string + default = "reserved-eu-fr-cluster-f884" +} +variable "mqcloud_queue_manager_size" { + description = "The queue manager sizes of deployment available. Deployment of lite queue managers for aws_us_east_1 and aws_eu_west_1 locations is not available." + type = string + default = "lite" +} +variable "mqcloud_queue_manager_version" { + description = "The MQ version of the queue manager." + type = string + default = "9.3.2_2" +} + +// Resource arguments for mqcloud_application +variable "mqcloud_application_service_instance_guid" { + description = "The GUID that uniquely identifies the MQ on Cloud service instance." + type = string + default = "Service Instance ID" +} +variable "mqcloud_application_name" { + description = "The name of the application - conforming to MQ rules." + type = string + default = "test-app" +} + +// Resource arguments for mqcloud_user +variable "mqcloud_user_service_instance_guid" { + description = "The GUID that uniquely identifies the MQ on Cloud service instance." + type = string + default = "Service Instance ID" +} + +// Data source arguments for mqcloud_application +variable "mqcloud_application_service_instance_guid" { + description = "The GUID that uniquely identifies the MQ on Cloud service instance." + type = string + default = "Service Instance ID" +} +variable "mqcloud_user_name" { + description = "The shortname of the user that will be used as the IBM MQ administrator in interactions with a queue manager for this service instance." + type = string + default = "name" +} + +variable "mqcloud_application_name" { + description = "The name of the application - conforming to MQ rules." + type = string + default = "name" +} +variable "mqcloud_user_name" { + description = "The shortname of the user that will be used as the IBM MQ administrator in interactions with a queue manager for this service instance." + type = string + default = "t0scie98o57a" +} +variable "mqcloud_user_email" { + description = "The email of the user." + type = string + default = "user@example.com" +} + +// Resource arguments for mqcloud_keystore_certificate +variable "mqcloud_keystore_certificate_service_instance_guid" { + description = "The GUID that uniquely identifies the MQ on Cloud service instance." + type = string + default = "Service Instance ID" +} +variable "mqcloud_keystore_certificate_queue_manager_id" { + description = "The id of the queue manager to retrieve its full details." + type = string + default = "Queue Manager ID" +} +variable "mqcloud_keystore_certificate_label" { + description = "Certificate label in queue manager store." + type = string + default = "label" +} + +// Resource arguments for mqcloud_truststore_certificate +variable "mqcloud_truststore_certificate_service_instance_guid" { + description = "The GUID that uniquely identifies the MQ on Cloud service instance." + type = string + default = "Service Instance ID" +} +variable "mqcloud_truststore_certificate_queue_manager_id" { + description = "The id of the queue manager to retrieve its full details." + type = string + default = "Queue Manager ID" +} + +variable "mqcloud_truststore_certificate_label" { + description = "Certificate label in queue manager store." + type = string + default = "label" +} + +// Data source arguments for mqcloud_queue_manager +variable "mqcloud_queue_manager_service_instance_guid" { + description = "The GUID that uniquely identifies the MQ on Cloud service instance." + type = string + default = "Service Instance ID" +} + +variable "mqcloud_queue_manager_name" { + description = "A queue manager name conforming to MQ restrictions." + type = string + default = "name" +} + +// Data source arguments for mqcloud_queue_manager_status +variable "mqcloud_queue_manager_status_service_instance_guid" { + description = "The GUID that uniquely identifies the MQ on Cloud service instance." + type = string + default = "Service Instance ID" +} +variable "mqcloud_queue_manager_status_queue_manager_id" { + description = "The id of the queue manager to retrieve its full details." + type = string + default = "Queue Manager ID" +} + +// Data source arguments for mqcloud_application +variable "mqcloud_application_service_instance_guid" { + description = "The GUID that uniquely identifies the MQ on Cloud service instance." + type = string + default = "Service Instance ID" +} + +variable "mqcloud_application_name" { + description = "The name of the application - conforming to MQ rules." + type = string + default = "name" +} + +// Data source arguments for mqcloud_user +variable "mqcloud_user_service_instance_guid" { + description = "The GUID that uniquely identifies the MQ on Cloud service instance." + type = string + default = "Service Instance ID" +} + +variable "mqcloud_user_name" { + description = "The shortname of the user that will be used as the IBM MQ administrator in interactions with a queue manager for this service instance." + type = string + default = "name" +} + +// Data source arguments for mqcloud_truststore_certificate +variable "mqcloud_truststore_certificate_service_instance_guid" { + description = "The GUID that uniquely identifies the MQ on Cloud service instance." + type = string + default = "Service Instance ID" +} +variable "mqcloud_truststore_certificate_queue_manager_id" { + description = "The id of the queue manager to retrieve its full details." + type = string + default = "Queue Manager ID" +} +variable "mqcloud_truststore_certificate_label" { + description = "Certificate label in queue manager store." + type = string + default = "label" +} + +// Data source arguments for mqcloud_keystore_certificate +variable "mqcloud_keystore_certificate_service_instance_guid" { + description = "The GUID that uniquely identifies the MQ on Cloud service instance." + type = string + default = "Service Instance ID" +} +variable "mqcloud_keystore_certificate_queue_manager_id" { + description = "The id of the queue manager to retrieve its full details." + type = string + default = "Queue Manager ID" +} +variable "mqcloud_keystore_certificate_label" { + description = "Certificate label in queue manager store." + type = string + default = "label" +} diff --git a/examples/ibm-mqcloud/versions.tf b/examples/ibm-mqcloud/versions.tf new file mode 100644 index 0000000000..54c9d03e8d --- /dev/null +++ b/examples/ibm-mqcloud/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_version = ">= 1.0" + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = "1.52.0-beta0" + } + } +} diff --git a/go.mod b/go.mod index 55322cd7a7..f7c431a96b 100644 --- a/go.mod +++ b/go.mod @@ -44,7 +44,7 @@ require ( github.com/google/uuid v1.3.0 github.com/hashicorp/go-uuid v1.0.3 github.com/hashicorp/go-version v1.6.0 - github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.0 + github.com/hashicorp/terraform-plugin-sdk/v2 v2.29.0 github.com/jinzhu/copier v0.3.2 github.com/minsikl/netscaler-nitro-go v0.0.0-20170827154432-5b14ce3643e3 github.com/mitchellh/go-homedir v1.1.0 @@ -53,7 +53,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/rook/rook v1.11.4 github.com/softlayer/softlayer-go v1.0.3 - golang.org/x/crypto v0.14.0 + golang.org/x/crypto v0.16.0 gopkg.in/yaml.v3 v3.0.1 gotest.tools v2.2.0+incompatible k8s.io/api v0.26.3 @@ -62,6 +62,7 @@ require ( ) require ( + github.com/IBM/mqcloud-go-sdk v0.0.0-20231207105140-14d858932788 github.com/IBM/sarama v1.41.2 k8s.io/utils v0.0.0-20230313181309-38a27ef9d749 sigs.k8s.io/controller-runtime v0.14.1 @@ -72,15 +73,17 @@ require ( cloud.google.com/go/monitoring v1.13.0 // indirect github.com/Logicalis/asn1 v0.0.0-20190312173541-d60463189a56 // indirect github.com/PromonLogicalis/asn1 v0.0.0-20190312173541-d60463189a56 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect github.com/agext/levenshtein v1.2.2 // indirect github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/apex/log v1.9.0 // indirect - github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect + github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v3 v3.2.2 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cloudflare/circl v1.3.3 // indirect github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 // indirect github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect github.com/coreos/pkg v0.0.0-20220810130054-c7d1c02cb6cf // indirect @@ -111,7 +114,7 @@ require ( github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.15.5 // indirect + github.com/go-playground/validator/v10 v10.16.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect @@ -125,30 +128,30 @@ require ( github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-plugin v1.5.0 // indirect + github.com/hashicorp/go-plugin v1.5.1 // indirect github.com/hashicorp/go-retryablehttp v0.7.4 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect github.com/hashicorp/go-sockaddr v1.0.2 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/hashicorp/hc-install v0.4.0 // indirect + github.com/hashicorp/hc-install v0.6.1 // indirect github.com/hashicorp/hcl v1.0.1-vault-5 // indirect - github.com/hashicorp/hcl/v2 v2.14.1 // indirect + github.com/hashicorp/hcl/v2 v2.19.1 // indirect github.com/hashicorp/logutils v1.0.0 // indirect - github.com/hashicorp/terraform-exec v0.17.3 // indirect - github.com/hashicorp/terraform-json v0.14.0 // indirect - github.com/hashicorp/terraform-plugin-go v0.14.0 // indirect - github.com/hashicorp/terraform-plugin-log v0.7.0 // indirect - github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c // indirect - github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 // indirect + github.com/hashicorp/terraform-exec v0.19.0 // indirect + github.com/hashicorp/terraform-json v0.17.1 // indirect + github.com/hashicorp/terraform-plugin-go v0.19.0 // indirect + github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect + github.com/hashicorp/terraform-registry-address v0.2.2 // indirect + github.com/hashicorp/terraform-svchost v0.1.1 // indirect github.com/hashicorp/vault v1.13.7 // indirect github.com/hashicorp/vault/api v1.9.2 // indirect github.com/hashicorp/vault/api/auth/approle v0.3.0 // indirect github.com/hashicorp/vault/sdk v0.10.0 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/hokaccha/go-prettyjson v0.0.0-20170213120834-e6b9231a2b1c // indirect - github.com/imdario/mergo v0.3.13 // indirect + github.com/imdario/mergo v0.3.15 // indirect github.com/jarcoal/httpmock v1.0.7 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect @@ -196,19 +199,22 @@ require ( github.com/stretchr/objx v0.5.0 // indirect github.com/stretchr/testify v1.8.4 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect - github.com/vmihailenco/msgpack/v4 v4.3.12 // indirect - github.com/vmihailenco/tagparser v0.1.1 // indirect - github.com/zclconf/go-cty v1.11.0 // indirect + github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + github.com/zclconf/go-cty v1.14.1 // indirect go.mongodb.org/mongo-driver v1.12.1 // indirect go.opentelemetry.io/otel v1.14.0 // indirect go.opentelemetry.io/otel/trace v1.14.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect - golang.org/x/net v0.17.0 // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/net v0.19.0 // indirect golang.org/x/oauth2 v0.7.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/term v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/sync v0.5.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/term v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.16.0 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect diff --git a/go.sum b/go.sum index 30e5ffdf8e..8df8dccea4 100644 --- a/go.sum +++ b/go.sum @@ -48,6 +48,7 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f/go.mod h1:sk5LnIjB/nIEU7yP5sDQExVm62wu0pBh3yrElngUisI= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/Azure/azure-sdk-for-go v36.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= @@ -155,6 +156,8 @@ github.com/IBM/ibm-hpcs-uko-sdk v0.0.20-beta/go.mod h1:MLVNHMYoKsvovJZ4v1gQCpIYt github.com/IBM/keyprotect-go-client v0.5.1/go.mod h1:5TwDM/4FRJq1ZOlwQL1xFahLWQ3TveR88VmL1u3njyI= github.com/IBM/keyprotect-go-client v0.12.2 h1:Cjxcqin9Pl0xz3MnxdiVd4v/eIa79xL3hQpSbwOr/DQ= github.com/IBM/keyprotect-go-client v0.12.2/go.mod h1:yr8h2noNgU8vcbs+vhqoXp3Lmv73PI0zAc6VMgFvWwM= +github.com/IBM/mqcloud-go-sdk v0.0.0-20231207105140-14d858932788 h1:cIT0YSzqMGqxM3OJQx1gp4gtYYy9U35O0tVdcFHOgwc= +github.com/IBM/mqcloud-go-sdk v0.0.0-20231207105140-14d858932788/go.mod h1:R4NBbDMygpHiFywUnOdV0UfBZap4HcHa3QXLlACr9TU= github.com/IBM/networking-go-sdk v0.42.2 h1:caqjx4jyFHi10Vlf3skHvlL6K3YJRVstsmCBmvdyqkA= github.com/IBM/networking-go-sdk v0.42.2/go.mod h1:lTUZwtUkMANMnrLHFIgRhHrkBfwASY/Iho1fabaPHxo= github.com/IBM/platform-services-go-sdk v0.54.0 h1:WjHWm9ZAJvlq07E1WXXtEe+d/B0sazWD6cEWVT7EMLU= @@ -186,8 +189,6 @@ github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030I github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= github.com/Masterminds/sprig/v3 v3.2.1 h1:n6EPaDyLSvCEa3frruQvAiHuNp2dhBlMSmkEr+HuzGc= github.com/Microsoft/go-winio v0.4.13/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= -github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= -github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= @@ -196,8 +197,8 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PromonLogicalis/asn1 v0.0.0-20190312173541-d60463189a56 h1:zL3Ph7RCZadAPb7QV0gMIDmjuZHFawNhoPZ5erh6TRw= github.com/PromonLogicalis/asn1 v0.0.0-20190312173541-d60463189a56/go.mod h1:nE9BGpMlMfM9Z3U+P+mWtcHNDwHcGctalMx1VTkODAY= -github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= -github.com/ProtonMail/go-crypto v0.0.0-20230626094100-7e9e0395ebec h1:vV3RryLxt42+ZIVOFbYJCH1jsZNTNmj2NYru5zfx+4E= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= @@ -211,8 +212,7 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw= -github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= -github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= +github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= @@ -232,7 +232,6 @@ github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1 github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/openwhisk-client-go v0.0.0-20200201143223-a804fb82d105 h1:k1wP1gZMrNJeXTz6a+3010NKC/ZvSffk07BzrLmYrmc= github.com/apache/openwhisk-client-go v0.0.0-20200201143223-a804fb82d105/go.mod h1:jLLKYP7+1+LFlIJW1n9U1gqeveLM1HIwa4ZHNOFxjPw= @@ -244,11 +243,9 @@ github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU= github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= -github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0 h1:MzVXffFUye+ZcSR6opIgz9Co7WcDx6ZcY+RjfFHoA0I= -github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= -github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= -github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= +github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= +github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= github.com/apple/foundationdb/bindings/go v0.0.0-20190411004307-cd5c9d91fad2/go.mod h1:OMVSB21p9+xQUIqlGizHPZfjK+SHws1ht+ZytVDoz9U= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= @@ -264,7 +261,6 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= @@ -297,6 +293,7 @@ github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyX github.com/briankassouf/jose v0.9.2-0.20180619214549-d2569464773f/go.mod h1:HQhVmdUf7dBNwIIdBTivnCDxcf6IZY3/zrb+uKSJz6Y= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= @@ -320,6 +317,7 @@ github.com/circonus-labs/circonusllhist v0.1.3 h1:TJH+oke8D16535+jHExHj4nQvzlZrj github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381/go.mod h1:e5+USP2j8Le2M0Jo3qKPFnNhuo1wueU4nWHCXBOfQ14= github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:tuijfIjZyjZaHq9xDUh0tNitwXshJpbLkqMOJv4H3do= github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:po7NpZ/QiTKzBKyrsEAxwnTamCoh8uDk/egRpQ7siIc= @@ -356,6 +354,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -405,8 +404,7 @@ github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful/v3 v3.10.0 h1:X4gma4HM7hFm6WMeAsTfqA0GOfdNoCzBIkHGoRLGXuM= github.com/emicklei/go-restful/v3 v3.10.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= -github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -432,7 +430,6 @@ github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= @@ -456,19 +453,13 @@ github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2H github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew= github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= -github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= -github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= -github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34= -github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0= -github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4= -github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= +github.com/go-git/go-git/v5 v5.9.0 h1:cD9SFA7sHVRdJ7AYck1ZaAa/yeuBvGPxwXDL8cxrObY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -596,8 +587,8 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24= -github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE= +github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= @@ -845,8 +836,8 @@ github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9 github.com/hashicorp/go-plugin v1.0.0/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= github.com/hashicorp/go-plugin v1.4.3/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= -github.com/hashicorp/go-plugin v1.5.0 h1:g6Lj3USwF5LaB8HlvCxPjN2X4nFE08ko2BJNVpl7TIE= -github.com/hashicorp/go-plugin v1.5.0/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= +github.com/hashicorp/go-plugin v1.5.1 h1:oGm7cWBaYIp3lJpx1RUEfLWophprE2EV/KUeqBYo+6k= +github.com/hashicorp/go-plugin v1.5.1/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/hashicorp/go-raftchunking v0.6.3-0.20191002164813-7e9e8525653a h1:FmnBDwGwlTgugDGbVxwV8UavqSMACbGrUpfc98yFLR4= github.com/hashicorp/go-raftchunking v0.6.3-0.20191002164813-7e9e8525653a/go.mod h1:xbXnmKqX9/+RhPkJ4zrEx4738HacP72aaUPlT2RZ4sU= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= @@ -891,7 +882,6 @@ github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/C github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.5.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= @@ -901,13 +891,13 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hc-install v0.4.0 h1:cZkRFr1WVa0Ty6x5fTvL1TuO1flul231rWkGH92oYYk= -github.com/hashicorp/hc-install v0.4.0/go.mod h1:5d155H8EC5ewegao9A4PUTMNPZaq+TbOzkJJZ4vrXeI= +github.com/hashicorp/hc-install v0.6.1 h1:IGxShH7AVhPaSuSJpKtVi/EFORNjO+OYVJJrAtGG2mY= +github.com/hashicorp/hc-install v0.6.1/go.mod h1:0fW3jpg+wraYSnFDJ6Rlie3RvLf1bIqVIkzoon4KoVE= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= -github.com/hashicorp/hcl/v2 v2.14.1 h1:x0BpjfZ+CYdbiz+8yZTQ+gdLO7IXvOut7Da+XJayx34= -github.com/hashicorp/hcl/v2 v2.14.1/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0= +github.com/hashicorp/hcl/v2 v2.19.1 h1://i05Jqznmb2EXqa39Nsvyan2o5XyMowW5fnCKW5RPI= +github.com/hashicorp/hcl/v2 v2.19.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE= github.com/hashicorp/hcp-sdk-go v0.23.0 h1:3WarkQSK0VzxJaH6psHIGQagag3ujL+NjWagZZHpiZM= github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= @@ -927,20 +917,20 @@ github.com/hashicorp/raft-snapshot v1.0.2-0.20190827162939-8117efcc5aab/go.mod h github.com/hashicorp/raft-snapshot v1.0.4 h1:EuDuayAJPdiDmVk1ygTDnG2zDzrs0/6/yBuma1IYSow= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.8.3/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k= -github.com/hashicorp/terraform-exec v0.17.3 h1:MX14Kvnka/oWGmIkyuyvL6POx25ZmKrjlaclkx3eErU= -github.com/hashicorp/terraform-exec v0.17.3/go.mod h1:+NELG0EqQekJzhvikkeQsOAZpsw0cv/03rbeQJqscAI= -github.com/hashicorp/terraform-json v0.14.0 h1:sh9iZ1Y8IFJLx+xQiKHGud6/TSUCM0N8e17dKDpqV7s= -github.com/hashicorp/terraform-json v0.14.0/go.mod h1:5A9HIWPkk4e5aeeXIBbkcOvaZbIYnAIkEyqP2pNSckM= -github.com/hashicorp/terraform-plugin-go v0.14.0 h1:ttnSlS8bz3ZPYbMb84DpcPhY4F5DsQtcAS7cHo8uvP4= -github.com/hashicorp/terraform-plugin-go v0.14.0/go.mod h1:2nNCBeRLaenyQEi78xrGrs9hMbulveqG/zDMQSvVJTE= -github.com/hashicorp/terraform-plugin-log v0.7.0 h1:SDxJUyT8TwN4l5b5/VkiTIaQgY6R+Y2BQ0sRZftGKQs= -github.com/hashicorp/terraform-plugin-log v0.7.0/go.mod h1:p4R1jWBXRTvL4odmEkFfDdhUjHf9zcs/BCoNHAc7IK4= -github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.0 h1:FtCLTiTcykdsURXPt/ku7fYXm3y19nbzbZcUxHx9RbI= -github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.0/go.mod h1:80wf5oad1tW+oLnbXS4UTYmDCrl7BuN1Q+IA91X1a4Y= -github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c h1:D8aRO6+mTqHfLsK/BC3j5OAoogv1WLRWzY1AaTo3rBg= -github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c/go.mod h1:Wn3Na71knbXc1G8Lh+yu/dQWWJeFQEpDeJMtWMtlmNI= -github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 h1:HKLsbzeOsfXmKNpr3GiT18XAblV0BjCbzL8KQAMZGa0= -github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg= +github.com/hashicorp/terraform-exec v0.19.0 h1:FpqZ6n50Tk95mItTSS9BjeOVUb4eg81SpgVtZNNtFSM= +github.com/hashicorp/terraform-exec v0.19.0/go.mod h1:tbxUpe3JKruE9Cuf65mycSIT8KiNPZ0FkuTE3H4urQg= +github.com/hashicorp/terraform-json v0.17.1 h1:eMfvh/uWggKmY7Pmb3T85u86E2EQg6EQHgyRwf3RkyA= +github.com/hashicorp/terraform-json v0.17.1/go.mod h1:Huy6zt6euxaY9knPAFKjUITn8QxUFIe9VuSzb4zn/0o= +github.com/hashicorp/terraform-plugin-go v0.19.0 h1:BuZx/6Cp+lkmiG0cOBk6Zps0Cb2tmqQpDM3iAtnhDQU= +github.com/hashicorp/terraform-plugin-go v0.19.0/go.mod h1:EhRSkEPNoylLQntYsk5KrDHTZJh9HQoumZXbOGOXmec= +github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0= +github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.29.0 h1:wcOKYwPI9IorAJEBLzgclh3xVolO7ZorYd6U1vnok14= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.29.0/go.mod h1:qH/34G25Ugdj5FcM95cSoXzUgIbgfhVLXCcEcYaMwq8= +github.com/hashicorp/terraform-registry-address v0.2.2 h1:lPQBg403El8PPicg/qONZJDC6YlgCVbWDtNmmZKtBno= +github.com/hashicorp/terraform-registry-address v0.2.2/go.mod h1:LtwNbCihUoUZ3RYriyS2wF/lGPB6gF9ICLRtuDk7hSo= +github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ= +github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc= github.com/hashicorp/vault v1.4.2/go.mod h1:500fLOj7p92Ys4X265LizqF78MzmHJUf1jV1zNJt060= github.com/hashicorp/vault v1.13.7 h1:4s/RullYWwTtWW7HzOKSR3SNzv4V2cgNo4ImvArnXpU= github.com/hashicorp/vault v1.13.7/go.mod h1:KgEsayEcTM6N6fSun+4OqofsiwmD8rN6TUPRqESLBJQ= @@ -1003,9 +993,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1: github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= -github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= +github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb v0.0.0-20190411212539-d24b7ba8c4c4/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= @@ -1014,7 +1003,6 @@ github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT github.com/jarcoal/httpmock v1.0.7 h1:d1a2VFpSdm5gtjhCPWsQHSnx8+5V3ms5431YwvmkuNk= github.com/jarcoal/httpmock v1.0.7/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jcmturner/aescts v1.0.1/go.mod h1:k9gJoDUf1GH5r2IBtBjwjDCoLELYxOcEhitdP8RL7qQ= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= @@ -1038,7 +1026,6 @@ github.com/jefferai/isbadcipher v0.0.0-20190226160619-51d2077c035f/go.mod h1:3J2 github.com/jefferai/jsonx v1.0.0 h1:Xoz0ZbmkpBvED5W9W1B5B/zc3Oiq7oXqiW7iRV3B6EI= github.com/jefferai/jsonx v1.0.0/go.mod h1:OGmqmi2tTeI/PS+qQfBDToLHHJIy/RMp24fPo8vFvoQ= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jinzhu/copier v0.3.2 h1:QdBOCbaouLDYaIPFfi1bKv5F5tPpeTwXe4sD0jqtz5w= @@ -1077,8 +1064,7 @@ github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaR github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kelseyhightower/envconfig v1.3.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= -github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck= -github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/keybase/go-crypto v0.0.0-20190403132359-d65b6b94177f/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= @@ -1107,7 +1093,6 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kube-object-storage/lib-bucket-provisioner v0.0.0-20221122204822-d1a8c34382f1 h1:dQEHhTfi+bSIOSViQrKY9PqJvZenD6tFz+3lPzux58o= github.com/kube-object-storage/lib-bucket-provisioner v0.0.0-20221122204822-d1a8c34382f1/go.mod h1:my+EVjOJLeQ9lUR9uVkxRvNNkhO2saSGIgzV8GZT9HY= github.com/kubernetes-csi/external-snapshotter/client/v4 v4.0.0/go.mod h1:YBCo4DoEeDndqvAn6eeu0vWM7QdXmHEeI9cFWplmBys= -github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= @@ -1136,7 +1121,6 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11/go.mod h1:Ah2dBMoxZEqk118as2T4u4fjfXarE0pPnMJaArZQZsI= -github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -1228,7 +1212,6 @@ github.com/nicksnyder/go-i18n v1.10.0 h1:5AzlPKvXBH4qBzmZ09Ua9Gipyruv6uApMcrNZdo github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q= github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2 h1:BQ1HW7hr4IVovMwWg0E0PYcyW8CzqDcVmaew9cujU4s= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce h1:RPclfga2SEJmgMmz2k+Mg7cowZ8yv4Trqw9UsJby758= github.com/nwaples/rardecode v1.0.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -1303,8 +1286,8 @@ github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+q github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ= github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= -github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= +github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= @@ -1352,6 +1335,7 @@ github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pires/go-proxyproto v0.6.1 h1:EBupykFmo22SDjv4fQVQd2J9NOoLPmyZA/15ldOGkPw= +github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -1444,9 +1428,7 @@ github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec/go.mod h1:gi+0 github.com/sasha-s/go-deadlock v0.2.0 h1:lMqc+fUb7RrFS3gQLtoQsJ7/6TV/pAIFvBsqX73DK8Y= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sethvargo/go-limiter v0.7.2 h1:FgC4N7RMpV5gMrUdda15FaFTkQ/L4fEqM7seXMs4oO8= github.com/shirou/gopsutil v2.19.9+incompatible h1:IrPVlK4nfwW10DF7pW+7YJKws9NkgNzWozwwWv9FsgY= @@ -1463,6 +1445,7 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/skeema/knownhosts v1.2.0 h1:h9r9cf0+u7wSE+M183ZtMGgOJKiL96brpaz5ekfJCpM= github.com/smartystreets/assertions v0.0.0-20180725160413-e900ae048470/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= @@ -1537,13 +1520,12 @@ github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= -github.com/vmihailenco/msgpack/v4 v4.3.12 h1:07s4sz9IReOgdikxLTKNbBdqDMLsjPKXwvCazn8G65U= -github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= -github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37wVyIuWY= -github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= +github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= +github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/vmware/govmomi v0.18.0 h1:f7QxSmP7meCtoAmiKZogvVbLInT+CZx6Px6K5rYsJZo= -github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= -github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= @@ -1569,12 +1551,8 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= -github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= -github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= -github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= -github.com/zclconf/go-cty v1.11.0 h1:726SxLdi2SDnjY+BStqB9J1hNp4+2WlzyXLuimibIe0= -github.com/zclconf/go-cty v1.11.0/go.mod h1:s9IfD1LK5ccNMSWCVFCE2rJfHiZgi7JijgeWIMfhLvA= -github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= +github.com/zclconf/go-cty v1.14.1 h1:t9fyA35fwjjUMcmL5hLER+e/rEPqrbCK1/OSE4SI9KA= +github.com/zclconf/go-cty v1.14.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= @@ -1629,7 +1607,6 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -1654,19 +1631,19 @@ golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1710,12 +1687,12 @@ golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1741,7 +1718,6 @@ golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1767,7 +1743,6 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= @@ -1791,8 +1766,9 @@ golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190130055435-99b60b757ec1/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1828,8 +1804,9 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1862,7 +1839,6 @@ golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1905,11 +1881,9 @@ golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1938,8 +1912,9 @@ golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.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/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1953,8 +1928,9 @@ golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= -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/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1975,8 +1951,9 @@ golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2065,8 +2042,9 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= -golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss= golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= +golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= +golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= 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= @@ -2253,7 +2231,6 @@ gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI 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/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -2268,7 +2245,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/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= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= diff --git a/ibm/acctest/acctest.go b/ibm/acctest/acctest.go index bee8b7cb2b..4e563d0cb8 100644 --- a/ibm/acctest/acctest.go +++ b/ibm/acctest/acctest.go @@ -122,6 +122,14 @@ var ( HpcsInstanceID string ) +// MQ on Cloud +var ( + MqcloudInstanceID string + MqcloudQueueManagerID string + MqcloudKSCertFilePath string + MqcloudTSCertFilePath string +) + // Secrets Manager var ( SecretsManagerInstanceID string @@ -1562,6 +1570,24 @@ func init() { if SatelliteSSHPubKey == "" { fmt.Println("[WARN] Set the environment variable IBM_SATELLITE_SSH_PUB_KEY with a ssh public key or ibm_satellite_* tests may fail") } + + MqcloudInstanceID = os.Getenv("IBM_MQCLOUD_INSTANCE_ID") + if MqcloudInstanceID == "" { + fmt.Println("[INFO] Set the environment variable IBM_MQCLOUD_INSTANCE_ID for ibm_mqcloud_queue_manager resource or datasource else tests will fail if this is not set correctly") + } + + MqcloudQueueManagerID = os.Getenv("IBM_MQCLOUD_QUEUEMANAGER_ID") + if MqcloudQueueManagerID == "" { + fmt.Println("[INFO] Set the environment variable IBM_MQCLOUD_QUEUEMANAGER_ID for ibm_mqcloud_queue_manager resource or datasource else tests will fail if this is not set correctly") + } + MqcloudKSCertFilePath = os.Getenv("IBM_MQCLOUD_KS_CERT_PATH") + if MqcloudKSCertFilePath == "" { + fmt.Println("[INFO] Set the environment variable IBM_MQCLOUD_KS_CERT_PATH for ibm_mqcloud_keystore_certificate resource or datasource else tests will fail if this is not set correctly") + } + MqcloudTSCertFilePath = os.Getenv("IBM_MQCLOUD_TS_CERT_PATH") + if MqcloudTSCertFilePath == "" { + fmt.Println("[INFO] Set the environment variable IBM_MQCLOUD_TS_CERT_PATH for ibm_mqcloud_truststore_certificate resource or datasource else tests will fail if this is not set correctly") + } } var ( @@ -1773,6 +1799,22 @@ func TestAccPreCheckSatelliteSSH(t *testing.T) { } } +func TestAccPreCheckMqcloud(t *testing.T) { + TestAccPreCheck(t) + if MqcloudInstanceID == "" { + t.Fatal("IBM_MQCLOUD_INSTANCE_ID must be set for acceptance tests") + } + if MqcloudQueueManagerID == "" { + t.Fatal("IBM_MQCLOUD_QUEUEMANAGER_ID must be set for acceptance tests") + } + if MqcloudTSCertFilePath == "" { + t.Fatal("IBM_MQCLOUD_TS_CERT_PATH must be set for acceptance tests") + } + if MqcloudKSCertFilePath == "" { + t.Fatal("IBM_MQCLOUD_KS_CERT_PATH must be set for acceptance tests") + } +} + func TestAccProviderFactories() map[string]func() (*schema.Provider, error) { return map[string]func() (*schema.Provider, error){ ProviderName: func() (*schema.Provider, error) { return provider.Provider(), nil }, diff --git a/ibm/conns/config.go b/ibm/conns/config.go index ff89bd307f..fd99350034 100644 --- a/ibm/conns/config.go +++ b/ibm/conns/config.go @@ -29,6 +29,7 @@ import ( "github.com/IBM/go-sdk-core/v5/core" cosconfig "github.com/IBM/ibm-cos-sdk-go-config/resourceconfigurationv1" kp "github.com/IBM/keyprotect-go-client" + "github.com/IBM/mqcloud-go-sdk/mqcloudv1" cisalertsv1 "github.com/IBM/networking-go-sdk/alertsv1" cisoriginpull "github.com/IBM/networking-go-sdk/authenticatedoriginpullapiv1" cisbotanalyticsv1 "github.com/IBM/networking-go-sdk/botanalyticsv1" @@ -299,6 +300,7 @@ type ClientSession interface { CodeEngineV2() (*codeengine.CodeEngineV2, error) ProjectV1() (*project.ProjectV1, error) UsageReportsV4() (*usagereportsv4.UsageReportsV4, error) + MqcloudV1() (*mqcloudv1.MqcloudV1, error) } type clientSession struct { @@ -624,6 +626,9 @@ type clientSession struct { // Usage Reports options usageReportsClient *usagereportsv4.UsageReportsV4 usageReportsClientErr error + + mqcloudClient *mqcloudv1.MqcloudV1 + mqcloudClientErr error } // Usage Reports @@ -1203,6 +1208,13 @@ func (session clientSession) ProjectV1() (*project.ProjectV1, error) { return session.projectClient, session.projectClientErr } +// MQ on Cloud +func (session clientSession) MqcloudV1() (*mqcloudv1.MqcloudV1, error) { + sessionMqcloudClient := session.mqcloudClient + sessionMqcloudClient.EnableRetries(0, 0) + return session.mqcloudClient, session.mqcloudClientErr +} + // ClientSession configures and returns a fully initialized ClientSession func (c *Config) ClientSession() (interface{}, error) { sess, err := newSession(c) @@ -1296,6 +1308,7 @@ func (c *Config) ClientSession() (interface{}, error) { session.cdToolchainClientErr = errEmptyBluemixCredentials session.codeEngineClientErr = errEmptyBluemixCredentials session.projectClientErr = errEmptyBluemixCredentials + session.mqcloudClientErr = errEmptyBluemixCredentials return session, nil } @@ -3245,6 +3258,33 @@ func (c *Config) ClientSession() (interface{}, error) { session.cdTektonPipelineClientErr = fmt.Errorf("Error occurred while configuring CD Tekton Pipeline service: %q", err) } + // MQ Cloud Service Configuration + mqCloudURL := ContructEndpoint(fmt.Sprintf("api.%s.mq2", c.Region), cloudEndpoint) + if c.Visibility == "private" || c.Visibility == "public-and-private" { + mqCloudURL = ContructEndpoint(fmt.Sprintf("api.private.%s.mq2", c.Region), cloudEndpoint) + } + if fileMap != nil && c.Visibility != "public-and-private" { + mqCloudURL = fileFallBack(fileMap, c.Visibility, "IBMCLOUD_MQCLOUD_CONFIG_ENDPOINT", c.Region, mqCloudURL) + } + + mqcloudClientOptions := &mqcloudv1.MqcloudV1Options{ + Authenticator: authenticator, + URL: EnvFallBack([]string{"IBMCLOUD_MQCLOUD_CONFIG_ENDPOINT"}, mqCloudURL), + } + + // Construct the service client for MQ Cloud. + session.mqcloudClient, err = mqcloudv1.NewMqcloudV1(mqcloudClientOptions) + if err != nil { + session.mqcloudClientErr = fmt.Errorf("Error occurred while configuring MQ Cloud service: %q", err) + } else { + // Enable retries for API calls + session.mqcloudClient.Service.EnableRetries(c.RetryCount, c.RetryDelay) + // Add custom header for analytics + session.mqcloudClient.SetDefaultHeaders(gohttp.Header{ + "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, + }) + } + // Construct the service options. codeEngineEndpoint := ContructEndpoint(fmt.Sprintf("api.%s.codeengine", c.Region), cloudEndpoint+"/v2") if c.Visibility == "private" || c.Visibility == "public-and-private" { diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go index 9a0e61277b..c00464a12b 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -39,6 +39,7 @@ import ( "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/kms" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/kubernetes" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/metricsrouter" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/mqcloud" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/power" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/project" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/pushnotification" @@ -743,6 +744,14 @@ func Provider() *schema.Provider { "ibm_metrics_router_targets": metricsrouter.DataSourceIBMMetricsRouterTargets(), "ibm_metrics_router_routes": metricsrouter.DataSourceIBMMetricsRouterRoutes(), + // MQ on Cloud + "ibm_mqcloud_queue_manager": mqcloud.DataSourceIbmMqcloudQueueManager(), + "ibm_mqcloud_queue_manager_status": mqcloud.DataSourceIbmMqcloudQueueManagerStatus(), + "ibm_mqcloud_application": mqcloud.DataSourceIbmMqcloudApplication(), + "ibm_mqcloud_user": mqcloud.DataSourceIbmMqcloudUser(), + "ibm_mqcloud_truststore_certificate": mqcloud.DataSourceIbmMqcloudTruststoreCertificate(), + "ibm_mqcloud_keystore_certificate": mqcloud.DataSourceIbmMqcloudKeystoreCertificate(), + // Security and Complaince Center(soon to be deprecated) "ibm_scc_account_location": scc.DataSourceIBMSccAccountLocation(), "ibm_scc_account_locations": scc.DataSourceIBMSccAccountLocations(), @@ -1276,6 +1285,13 @@ func Provider() *schema.Provider { "ibm_metrics_router_route": metricsrouter.ResourceIBMMetricsRouterRoute(), "ibm_metrics_router_settings": metricsrouter.ResourceIBMMetricsRouterSettings(), + // MQ on Cloud + "ibm_mqcloud_queue_manager": mqcloud.ResourceIbmMqcloudQueueManager(), + "ibm_mqcloud_application": mqcloud.ResourceIbmMqcloudApplication(), + "ibm_mqcloud_user": mqcloud.ResourceIbmMqcloudUser(), + "ibm_mqcloud_keystore_certificate": mqcloud.ResourceIbmMqcloudKeystoreCertificate(), + "ibm_mqcloud_truststore_certificate": mqcloud.ResourceIbmMqcloudTruststoreCertificate(), + // Security and Compliance Center(soon to be deprecated) "ibm_scc_account_settings": scc.ResourceIBMSccAccountSettings(), "ibm_scc_rule_attachment": scc.ResourceIBMSccRuleAttachment(), @@ -1461,6 +1477,13 @@ func Validator() validate.ValidatorDict { "ibm_hpcs_key_template": hpcs.ResourceIbmKeyTemplateValidator(), "ibm_hpcs_vault": hpcs.ResourceIbmVaultValidator(), + // MQ on Cloud + "ibm_mqcloud_queue_manager": mqcloud.ResourceIbmMqcloudQueueManagerValidator(), + "ibm_mqcloud_application": mqcloud.ResourceIbmMqcloudApplicationValidator(), + "ibm_mqcloud_user": mqcloud.ResourceIbmMqcloudUserValidator(), + "ibm_mqcloud_keystore_certificate": mqcloud.ResourceIbmMqcloudKeystoreCertificateValidator(), + "ibm_mqcloud_truststore_certificate": mqcloud.ResourceIbmMqcloudTruststoreCertificateValidator(), + "ibm_is_backup_policy": vpc.ResourceIBMIsBackupPolicyValidator(), "ibm_is_backup_policy_plan": vpc.ResourceIBMIsBackupPolicyPlanValidator(), diff --git a/ibm/service/mqcloud/README.md b/ibm/service/mqcloud/README.md new file mode 100644 index 0000000000..c95818ac94 --- /dev/null +++ b/ibm/service/mqcloud/README.md @@ -0,0 +1,11 @@ +# Terraform IBM Provider + +This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. + + +## Handy Links +* [Find out about contributing](../../../CONTRIBUTING.md) to the IBM provider! +* IBM Provider Docs: [Home](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs) +* IBM Provider Docs: [One of the resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/mqcloud_queue_manager) +* IBM API Docs: [IBM API Docs for ]() +* IBM SDK: [IBM SDK for ](https://github.com/IBM/appconfiguration-go-admin-sdk/tree/master/mqcloudv1) diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_application.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_application.go new file mode 100644 index 0000000000..9cef9c4831 --- /dev/null +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_application.go @@ -0,0 +1,167 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package mqcloud + +import ( + "context" + "fmt" + + "time" + + "github.com/IBM/mqcloud-go-sdk/mqcloudv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +func DataSourceIbmMqcloudApplication() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIbmMqcloudApplicationRead, + + Schema: map[string]*schema.Schema{ + "service_instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "The GUID that uniquely identifies the MQ on Cloud service instance.", + }, + "name": { + Type: schema.TypeString, + Optional: true, + Description: "The name of the application - conforming to MQ rules.", + }, + "applications": { + Type: schema.TypeList, + Computed: true, + Description: "List of applications.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the application which was allocated on creation, and can be used for delete calls.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the application - conforming to MQ rules.", + }, + "create_api_key_uri": { + Type: schema.TypeString, + Computed: true, + Description: "The URI to create a new apikey for the application.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this application.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIbmMqcloudApplicationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return diag.FromErr(err) + } + + err = checkSIPlan(d, meta) + if err != nil { + return diag.FromErr(fmt.Errorf("Read Application failed %s", err)) + } + + serviceInstanceGuid := d.Get("service_instance_guid").(string) + + // Support for pagination + offset := int64(0) + limit := int64(25) + allItems := []mqcloudv1.ApplicationDetails{} + + for { + listApplicationsOptions := &mqcloudv1.ListApplicationsOptions{ + ServiceInstanceGuid: &serviceInstanceGuid, + Limit: &limit, + Offset: &offset, + } + + result, response, err := mqcloudClient.ListApplicationsWithContext(context, listApplicationsOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error Getting Applications %s\n%s", err, response)) + } + if result == nil { + return diag.FromErr(fmt.Errorf("List Applications returned nil")) + } + + allItems = append(allItems, result.Applications...) + + // Check if the number of returned records is less than the limit + if int64(len(result.Applications)) < limit { + break + } + + offset += limit + } + + // Use the provided filter argument and construct a new list with only the requested resource(s) + var matchApplications []mqcloudv1.ApplicationDetails + var name string + var suppliedFilter bool + + if v, ok := d.GetOk("name"); ok { + name = v.(string) + suppliedFilter = true + for _, data := range allItems { + if *data.Name == name { + matchApplications = append(matchApplications, data) + } + } + } else { + matchApplications = allItems + } + + allItems = matchApplications + + if suppliedFilter { + if len(allItems) == 0 { + return diag.FromErr(fmt.Errorf("No Applications found with name %s", name)) + } + d.SetId(name) + } else { + d.SetId(dataSourceIbmMqcloudApplicationID(d)) + } + + mapSlice := []map[string]interface{}{} + for _, modelItem := range allItems { + modelItem := modelItem + modelMap, err := dataSourceIbmMqcloudApplicationApplicationDetailsToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + mapSlice = append(mapSlice, modelMap) + } + + if err = d.Set("applications", mapSlice); err != nil { + return diag.FromErr(fmt.Errorf("Error setting applications %s", err)) + } + + return nil +} + +// dataSourceIbmMqcloudApplicationID returns a reasonable ID for the list. +func dataSourceIbmMqcloudApplicationID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceIbmMqcloudApplicationApplicationDetailsToMap(model *mqcloudv1.ApplicationDetails) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = model.ID + modelMap["name"] = model.Name + modelMap["create_api_key_uri"] = model.CreateApiKeyURI + modelMap["href"] = model.Href + return modelMap, nil +} diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_application_test.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_application_test.go new file mode 100644 index 0000000000..1c9f1d7347 --- /dev/null +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_application_test.go @@ -0,0 +1,87 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package mqcloud_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIbmMqcloudApplicationDataSourceBasic(t *testing.T) { + applicationDetailsServiceInstanceGuid := acc.MqcloudInstanceID + applicationDetailsName := "appdsbasic" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudApplicationDataSourceConfigBasic(applicationDetailsServiceInstanceGuid, applicationDetailsName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_application.mqcloud_application_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_application.mqcloud_application_instance", "service_instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_application.mqcloud_application_instance", "applications.#"), + resource.TestCheckResourceAttr("data.ibm_mqcloud_application.mqcloud_application_instance", "applications.0.name", applicationDetailsName), + ), + }, + }, + }) +} + +func TestAccIbmMqcloudApplicationDataSourceAllArgs(t *testing.T) { + applicationDetailsServiceInstanceGuid := acc.MqcloudInstanceID + applicationDetailsName := "appdsargs" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudApplicationDataSourceConfig(applicationDetailsServiceInstanceGuid, applicationDetailsName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_application.mqcloud_application_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_application.mqcloud_application_instance", "service_instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_application.mqcloud_application_instance", "name"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_application.mqcloud_application_instance", "applications.#"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_application.mqcloud_application_instance", "applications.0.id"), + resource.TestCheckResourceAttr("data.ibm_mqcloud_application.mqcloud_application_instance", "applications.0.name", applicationDetailsName), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_application.mqcloud_application_instance", "applications.0.create_api_key_uri"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_application.mqcloud_application_instance", "applications.0.href"), + ), + }, + }, + }) +} + +func testAccCheckIbmMqcloudApplicationDataSourceConfigBasic(applicationDetailsServiceInstanceGuid string, applicationDetailsName string) string { + return fmt.Sprintf(` + resource "ibm_mqcloud_application" "mqcloud_application_instance" { + service_instance_guid = "%s" + name = "%s" + } + + data "ibm_mqcloud_application" "mqcloud_application_instance" { + service_instance_guid = ibm_mqcloud_application.mqcloud_application_instance.service_instance_guid + name = ibm_mqcloud_application.mqcloud_application_instance.name + } + `, applicationDetailsServiceInstanceGuid, applicationDetailsName) +} + +func testAccCheckIbmMqcloudApplicationDataSourceConfig(applicationDetailsServiceInstanceGuid string, applicationDetailsName string) string { + return fmt.Sprintf(` + resource "ibm_mqcloud_application" "mqcloud_application_instance" { + service_instance_guid = "%s" + name = "%s" + } + + data "ibm_mqcloud_application" "mqcloud_application_instance" { + service_instance_guid = ibm_mqcloud_application.mqcloud_application_instance.service_instance_guid + name = ibm_mqcloud_application.mqcloud_application_instance.name + } + `, applicationDetailsServiceInstanceGuid, applicationDetailsName) +} diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_keystore_certificate.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_keystore_certificate.go new file mode 100644 index 0000000000..0f27f37fa3 --- /dev/null +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_keystore_certificate.go @@ -0,0 +1,223 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package mqcloud + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/mqcloud-go-sdk/mqcloudv1" +) + +func DataSourceIbmMqcloudKeystoreCertificate() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIbmMqcloudKeystoreCertificateRead, + + Schema: map[string]*schema.Schema{ + "service_instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "The GUID that uniquely identifies the MQ on Cloud service instance.", + }, + "queue_manager_id": { + Type: schema.TypeString, + Required: true, + Description: "The id of the queue manager to retrieve its full details.", + }, + "label": { + Type: schema.TypeString, + Optional: true, + Description: "Certificate label in queue manager store.", + }, + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total count of key store certificates.", + }, + "key_store": { + Type: schema.TypeList, + Computed: true, + Description: "The list of key store certificates.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "ID of the certificate.", + }, + "label": { + Type: schema.TypeString, + Computed: true, + Description: "Certificate label in queue manager store.", + }, + "certificate_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of certificate.", + }, + "fingerprint_sha256": { + Type: schema.TypeString, + Computed: true, + Description: "Fingerprint SHA256.", + }, + "subject_dn": { + Type: schema.TypeString, + Computed: true, + Description: "Subject's Distinguished Name.", + }, + "subject_cn": { + Type: schema.TypeString, + Computed: true, + Description: "Subject's Common Name.", + }, + "issuer_dn": { + Type: schema.TypeString, + Computed: true, + Description: "Issuer's Distinguished Name.", + }, + "issuer_cn": { + Type: schema.TypeString, + Computed: true, + Description: "Issuer's Common Name.", + }, + "issued": { + Type: schema.TypeString, + Computed: true, + Description: "Date certificate was issued.", + }, + "expiry": { + Type: schema.TypeString, + Computed: true, + Description: "Expiry date for the certificate.", + }, + "is_default": { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether it is the queue manager's default certificate.", + }, + "dns_names_total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total count of dns names.", + }, + "dns_names": { + Type: schema.TypeList, + Computed: true, + Description: "The list of DNS names.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this key store certificate.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIbmMqcloudKeystoreCertificateRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return diag.FromErr(err) + } + err = checkSIPlan(d, meta) + if err != nil { + return diag.FromErr(fmt.Errorf("Read Keystore Certificate failed %s", err)) + } + + listKeyStoreCertificatesOptions := &mqcloudv1.ListKeyStoreCertificatesOptions{} + + listKeyStoreCertificatesOptions.SetServiceInstanceGuid(d.Get("service_instance_guid").(string)) + listKeyStoreCertificatesOptions.SetQueueManagerID(d.Get("queue_manager_id").(string)) + + keyStoreCertificateDetailsCollection, response, err := mqcloudClient.ListKeyStoreCertificatesWithContext(context, listKeyStoreCertificatesOptions) + if err != nil { + log.Printf("[DEBUG] ListKeyStoreCertificatesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListKeyStoreCertificatesWithContext failed %s\n%s", err, response)) + } + + // Use the provided filter argument and construct a new list with only the requested resource(s) + var matchKeyStore []mqcloudv1.KeyStoreCertificateDetails + var label string + var suppliedFilter bool + + if v, ok := d.GetOk("label"); ok { + label = v.(string) + suppliedFilter = true + for _, data := range keyStoreCertificateDetailsCollection.KeyStore { + if *data.Label == label { + matchKeyStore = append(matchKeyStore, data) + } + } + } else { + matchKeyStore = keyStoreCertificateDetailsCollection.KeyStore + } + keyStoreCertificateDetailsCollection.KeyStore = matchKeyStore + + if suppliedFilter { + if len(keyStoreCertificateDetailsCollection.KeyStore) == 0 { + return diag.FromErr(fmt.Errorf("no KeyStore found with label %s", label)) + } + d.SetId(label) + } else { + d.SetId(dataSourceIbmMqcloudKeystoreCertificateID(d)) + } + + if err = d.Set("total_count", flex.IntValue(keyStoreCertificateDetailsCollection.TotalCount)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting total_count: %s", err)) + } + + keyStore := []map[string]interface{}{} + if keyStoreCertificateDetailsCollection.KeyStore != nil { + for _, modelItem := range keyStoreCertificateDetailsCollection.KeyStore { + modelItem := modelItem + modelMap, err := dataSourceIbmMqcloudKeystoreCertificateKeyStoreCertificateDetailsToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + keyStore = append(keyStore, modelMap) + } + } + if err = d.Set("key_store", keyStore); err != nil { + return diag.FromErr(fmt.Errorf("Error setting key_store %s", err)) + } + + return nil +} + +// dataSourceIbmMqcloudKeystoreCertificateID returns a reasonable ID for the list. +func dataSourceIbmMqcloudKeystoreCertificateID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceIbmMqcloudKeystoreCertificateKeyStoreCertificateDetailsToMap(model *mqcloudv1.KeyStoreCertificateDetails) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = model.ID + modelMap["label"] = model.Label + modelMap["certificate_type"] = model.CertificateType + modelMap["fingerprint_sha256"] = model.FingerprintSha256 + modelMap["subject_dn"] = model.SubjectDn + modelMap["subject_cn"] = model.SubjectCn + modelMap["issuer_dn"] = model.IssuerDn + modelMap["issuer_cn"] = model.IssuerCn + modelMap["issued"] = model.Issued.String() + modelMap["expiry"] = model.Expiry.String() + modelMap["is_default"] = model.IsDefault + modelMap["dns_names_total_count"] = flex.IntValue(model.DnsNamesTotalCount) + modelMap["dns_names"] = model.DnsNames + modelMap["href"] = model.Href + return modelMap, nil +} diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_keystore_certificate_test.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_keystore_certificate_test.go new file mode 100644 index 0000000000..9f0b3218e6 --- /dev/null +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_keystore_certificate_test.go @@ -0,0 +1,107 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package mqcloud_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIbmMqcloudKeystoreCertificateDataSourceBasic(t *testing.T) { + keyStoreCertificateDetailsServiceInstanceGuid := acc.MqcloudInstanceID + keyStoreCertificateDetailsQueueManagerID := acc.MqcloudQueueManagerID + keyStoreCertificateDetailsLabel := fmt.Sprintf("tf_label_%d", acctest.RandIntRange(10, 100)) + keyStoreCertificateDetailsCertificateFile := acc.MqcloudKSCertFilePath + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudKeystoreCertificateDataSourceConfigBasic(keyStoreCertificateDetailsServiceInstanceGuid, keyStoreCertificateDetailsQueueManagerID, keyStoreCertificateDetailsLabel, keyStoreCertificateDetailsCertificateFile), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "service_instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "queue_manager_id"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "key_store.#"), + resource.TestCheckResourceAttr("data.ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "key_store.0.label", keyStoreCertificateDetailsLabel), + ), + }, + }, + }) +} + +func TestAccIbmMqcloudKeystoreCertificateDataSourceAllArgs(t *testing.T) { + keyStoreCertificateDetailsServiceInstanceGuid := acc.MqcloudInstanceID + keyStoreCertificateDetailsQueueManagerID := acc.MqcloudQueueManagerID + keyStoreCertificateDetailsLabel := fmt.Sprintf("tf_label_%d", acctest.RandIntRange(10, 100)) + keyStoreCertificateDetailsCertificateFile := acc.MqcloudKSCertFilePath + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudKeystoreCertificateDataSourceConfig(keyStoreCertificateDetailsServiceInstanceGuid, keyStoreCertificateDetailsQueueManagerID, keyStoreCertificateDetailsLabel, keyStoreCertificateDetailsCertificateFile), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "service_instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "queue_manager_id"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "label"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "total_count"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "key_store.#"), + resource.TestCheckResourceAttr("data.ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "key_store.0.label", keyStoreCertificateDetailsLabel), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "key_store.0.certificate_type"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "key_store.0.fingerprint_sha256"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "key_store.0.subject_dn"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "key_store.0.subject_cn"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "key_store.0.issuer_dn"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "key_store.0.issuer_cn"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "key_store.0.issued"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "key_store.0.expiry"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "key_store.0.is_default"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "key_store.0.dns_names_total_count"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "key_store.0.href"), + ), + }, + }, + }) +} + +func testAccCheckIbmMqcloudKeystoreCertificateDataSourceConfigBasic(keyStoreCertificateDetailsServiceInstanceGuid string, keyStoreCertificateDetailsQueueManagerID string, keyStoreCertificateDetailsLabel string, keyStoreCertificateDetailsCertificateFile string) string { + return fmt.Sprintf(` + resource "ibm_mqcloud_keystore_certificate" "mqcloud_keystore_certificate_instance" { + service_instance_guid = "%s" + queue_manager_id = "%s" + label = "%s" + certificate_file = "%s" + } + + data "ibm_mqcloud_keystore_certificate" "mqcloud_keystore_certificate_instance" { + service_instance_guid = ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance.service_instance_guid + queue_manager_id = ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance.queue_manager_id + label = ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance.label + } + `, keyStoreCertificateDetailsServiceInstanceGuid, keyStoreCertificateDetailsQueueManagerID, keyStoreCertificateDetailsLabel, keyStoreCertificateDetailsCertificateFile) +} + +func testAccCheckIbmMqcloudKeystoreCertificateDataSourceConfig(keyStoreCertificateDetailsServiceInstanceGuid string, keyStoreCertificateDetailsQueueManagerID string, keyStoreCertificateDetailsLabel string, keyStoreCertificateDetailsCertificateFile string) string { + return fmt.Sprintf(` + resource "ibm_mqcloud_keystore_certificate" "mqcloud_keystore_certificate_instance" { + service_instance_guid = "%s" + queue_manager_id = "%s" + label = "%s" + certificate_file = "%s" + } + + data "ibm_mqcloud_keystore_certificate" "mqcloud_keystore_certificate_instance" { + service_instance_guid = ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance.service_instance_guid + queue_manager_id = ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance.queue_manager_id + label = ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance.label + } + `, keyStoreCertificateDetailsServiceInstanceGuid, keyStoreCertificateDetailsQueueManagerID, keyStoreCertificateDetailsLabel, keyStoreCertificateDetailsCertificateFile) +} diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager.go new file mode 100644 index 0000000000..42774e4bce --- /dev/null +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager.go @@ -0,0 +1,232 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package mqcloud + +import ( + "context" + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/mqcloud-go-sdk/mqcloudv1" +) + +func DataSourceIbmMqcloudQueueManager() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIbmMqcloudQueueManagerRead, + + Schema: map[string]*schema.Schema{ + "service_instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "The GUID that uniquely identifies the MQ on Cloud service instance.", + }, + "name": { + Type: schema.TypeString, + Optional: true, + Description: "A queue manager name conforming to MQ restrictions.", + }, + "queue_managers": { + Type: schema.TypeList, + Computed: true, + Description: "List of queue managers.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the queue manager which was allocated on creation, and can be used for delete calls.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "A queue manager name conforming to MQ restrictions.", + }, + "display_name": { + Type: schema.TypeString, + Computed: true, + Description: "A displayable name for the queue manager - limited only in length.", + }, + "location": { + Type: schema.TypeString, + Computed: true, + Description: "The locations in which the queue manager could be deployed.", + }, + "size": { + Type: schema.TypeString, + Computed: true, + Description: "The queue manager sizes of deployment available. Deployment of lite queue managers for aws_us_east_1 and aws_eu_west_1 locations is not available.", + }, + "status_uri": { + Type: schema.TypeString, + Computed: true, + Description: "A reference uri to get deployment status of the queue manager.", + }, + "version": { + Type: schema.TypeString, + Computed: true, + Description: "The MQ version of the queue manager.", + }, + "web_console_url": { + Type: schema.TypeString, + Computed: true, + Description: "The url through which to access the web console for this queue manager.", + }, + "rest_api_endpoint_url": { + Type: schema.TypeString, + Computed: true, + Description: "The url through which to access REST APIs for this queue manager.", + }, + "administrator_api_endpoint_url": { + Type: schema.TypeString, + Computed: true, + Description: "The url through which to access the Admin REST APIs for this queue manager.", + }, + "connection_info_uri": { + Type: schema.TypeString, + Computed: true, + Description: "The uri through which the CDDT for this queue manager can be obtained.", + }, + "date_created": { + Type: schema.TypeString, + Computed: true, + Description: "RFC3339 formatted UTC date for when the queue manager was created.", + }, + "upgrade_available": { + Type: schema.TypeBool, + Computed: true, + Description: "Describes whether an upgrade is available for this queue manager.", + }, + "available_upgrade_versions_uri": { + Type: schema.TypeString, + Computed: true, + Description: "The uri through which the available versions to upgrade to can be found for this queue manager.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this queue manager.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIbmMqcloudQueueManagerRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return diag.FromErr(err) + } + + err = checkSIPlan(d, meta) + if err != nil { + return diag.FromErr(fmt.Errorf("Read Queue Manager failed %s", err)) + } + + serviceInstanceGuid := d.Get("service_instance_guid").(string) + + // Support for pagination + offset := int64(0) + limit := int64(25) + allItems := []mqcloudv1.QueueManagerDetails{} + + for { + listQueueManagersOptions := &mqcloudv1.ListQueueManagersOptions{ + ServiceInstanceGuid: &serviceInstanceGuid, + Limit: &limit, + Offset: &offset, + } + + result, response, err := mqcloudClient.ListQueueManagersWithContext(context, listQueueManagersOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error Getting QueueManagers %s\n%s", err, response)) + } + if result == nil { + return diag.FromErr(fmt.Errorf("List QueueManagers returned nil")) + } + + allItems = append(allItems, result.QueueManagers...) + + // Check if the number of returned records is less than the limit + if int64(len(result.QueueManagers)) < limit { + break + } + + offset += limit + } + + // Use the provided filter argument and construct a new list with only the requested resource(s) + var matchQueueManagers []mqcloudv1.QueueManagerDetails + var name string + var suppliedFilter bool + + if v, ok := d.GetOk("name"); ok { + name = v.(string) + suppliedFilter = true + for _, data := range allItems { + if *data.Name == name { + matchQueueManagers = append(matchQueueManagers, data) + } + } + } else { + matchQueueManagers = allItems + } + + allItems = matchQueueManagers + + if suppliedFilter { + if len(allItems) == 0 { + return diag.FromErr(fmt.Errorf("No Queue Managers found with name %s", name)) + } + d.SetId(name) + } else { + d.SetId(dataSourceIbmMqcloudQueueManagerID(d)) + } + + mapSlice := []map[string]interface{}{} + for _, modelItem := range allItems { + modelItem := modelItem + modelMap, err := dataSourceIbmMqcloudQueueManagerQueueManagerDetailsToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + mapSlice = append(mapSlice, modelMap) + } + + if err = d.Set("queue_managers", mapSlice); err != nil { + return diag.FromErr(fmt.Errorf("Error setting queue_managers %s", err)) + } + + return nil +} + +// dataSourceIbmMqcloudQueueManagerID returns a reasonable ID for the list. +func dataSourceIbmMqcloudQueueManagerID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceIbmMqcloudQueueManagerQueueManagerDetailsToMap(model *mqcloudv1.QueueManagerDetails) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = model.ID + modelMap["name"] = model.Name + modelMap["display_name"] = model.DisplayName + modelMap["location"] = model.Location + modelMap["size"] = model.Size + modelMap["status_uri"] = model.StatusURI + modelMap["version"] = model.Version + modelMap["web_console_url"] = model.WebConsoleURL + modelMap["rest_api_endpoint_url"] = model.RestApiEndpointURL + modelMap["administrator_api_endpoint_url"] = model.AdministratorApiEndpointURL + modelMap["connection_info_uri"] = model.ConnectionInfoURI + modelMap["date_created"] = model.DateCreated.String() + modelMap["upgrade_available"] = model.UpgradeAvailable + modelMap["available_upgrade_versions_uri"] = model.AvailableUpgradeVersionsURI + modelMap["href"] = model.Href + return modelMap, nil +} diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_status.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_status.go new file mode 100644 index 0000000000..835949afed --- /dev/null +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_status.go @@ -0,0 +1,77 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package mqcloud + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/mqcloud-go-sdk/mqcloudv1" +) + +func DataSourceIbmMqcloudQueueManagerStatus() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIbmMqcloudQueueManagerStatusRead, + + Schema: map[string]*schema.Schema{ + "service_instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "The GUID that uniquely identifies the MQ on Cloud service instance.", + }, + "queue_manager_id": { + Type: schema.TypeString, + Required: true, + Description: "The id of the queue manager to retrieve its full details.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The deploying and failed states are not queue manager states, they are states which can occur when the request to deploy has been fired, or with that request has failed without producing a queue manager to have any state. The other states map to the queue manager states. State \"ending\" is either quiesing or ending immediately. State \"ended\" is either ended normally or endedimmediately. The others map one to one with queue manager states.", + }, + }, + } +} + +func dataSourceIbmMqcloudQueueManagerStatusRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return diag.FromErr(err) + } + + err = checkSIPlan(d, meta) + if err != nil { + return diag.FromErr(fmt.Errorf("Read Queue Manager Status failed %s", err)) + } + + getQueueManagerStatusOptions := &mqcloudv1.GetQueueManagerStatusOptions{} + + getQueueManagerStatusOptions.SetServiceInstanceGuid(d.Get("service_instance_guid").(string)) + getQueueManagerStatusOptions.SetQueueManagerID(d.Get("queue_manager_id").(string)) + + queueManagerStatus, response, err := mqcloudClient.GetQueueManagerStatusWithContext(context, getQueueManagerStatusOptions) + if err != nil { + log.Printf("[DEBUG] GetQueueManagerStatusWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetQueueManagerStatusWithContext failed %s\n%s", err, response)) + } + + d.SetId(dataSourceIbmMqcloudQueueManagerStatusID(d)) + + if err = d.Set("status", queueManagerStatus.Status); err != nil { + return diag.FromErr(fmt.Errorf("Error setting status: %s", err)) + } + + return nil +} + +// dataSourceIbmMqcloudQueueManagerStatusID returns a reasonable ID for the list. +func dataSourceIbmMqcloudQueueManagerStatusID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_status_test.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_status_test.go new file mode 100644 index 0000000000..c09b3d5ba6 --- /dev/null +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_status_test.go @@ -0,0 +1,44 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package mqcloud_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIbmMqcloudQueueManagerStatusDataSourceBasic(t *testing.T) { + t.Parallel() + service_instance_guid := acc.MqcloudInstanceID + queue_manager_id := acc.MqcloudQueueManagerID + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudQueueManagerStatusDataSourceConfigBasic(service_instance_guid, queue_manager_id), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_queue_manager_status.mqcloud_queue_manager_status_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_queue_manager_status.mqcloud_queue_manager_status_instance", "service_instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_queue_manager_status.mqcloud_queue_manager_status_instance", "queue_manager_id"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_queue_manager_status.mqcloud_queue_manager_status_instance", "status"), + ), + }, + }, + }) +} + +func testAccCheckIbmMqcloudQueueManagerStatusDataSourceConfigBasic(service_instance_guid string, queue_manager_id string) string { + return fmt.Sprintf(` + data "ibm_mqcloud_queue_manager_status" "mqcloud_queue_manager_status_instance" { + service_instance_guid = "%s" + queue_manager_id = "%s" + } + `, service_instance_guid, queue_manager_id) +} diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_test.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_test.go new file mode 100644 index 0000000000..69f9690370 --- /dev/null +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_test.go @@ -0,0 +1,114 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package mqcloud_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIbmMqcloudQueueManagerDataSourceBasic(t *testing.T) { + t.Parallel() + queueManagerDetailsServiceInstanceGuid := acc.MqcloudInstanceID + queueManagerDetailsName := "queue_manager_ds_basic" + queueManagerDetailsLocation := "ibmcloud_eu_de" + queueManagerDetailsSize := "small" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudQueueManagerDataSourceConfigBasic(queueManagerDetailsServiceInstanceGuid, queueManagerDetailsName, queueManagerDetailsLocation, queueManagerDetailsSize), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "service_instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "queue_managers.#"), + resource.TestCheckResourceAttr("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "queue_managers.0.name", queueManagerDetailsName), + resource.TestCheckResourceAttr("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "queue_managers.0.location", queueManagerDetailsLocation), + resource.TestCheckResourceAttr("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "queue_managers.0.size", queueManagerDetailsSize), + ), + }, + }, + }) +} + +func TestAccIbmMqcloudQueueManagerDataSourceAllArgs(t *testing.T) { + t.Parallel() + queueManagerDetailsServiceInstanceGuid := acc.MqcloudInstanceID + queueManagerDetailsName := "queue_manager_ds_allargs" + queueManagerDetailsDisplayName := "queue_manager_ds_allargs" + queueManagerDetailsLocation := "ibmcloud_eu_de" + queueManagerDetailsSize := "small" + queueManagerDetailsVersion := "9.3.3_3" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudQueueManagerDataSourceConfig(queueManagerDetailsServiceInstanceGuid, queueManagerDetailsName, queueManagerDetailsDisplayName, queueManagerDetailsLocation, queueManagerDetailsSize, queueManagerDetailsVersion), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "service_instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "name"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "queue_managers.#"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "queue_managers.0.id"), + resource.TestCheckResourceAttr("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "queue_managers.0.name", queueManagerDetailsName), + resource.TestCheckResourceAttr("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "queue_managers.0.display_name", queueManagerDetailsDisplayName), + resource.TestCheckResourceAttr("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "queue_managers.0.location", queueManagerDetailsLocation), + resource.TestCheckResourceAttr("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "queue_managers.0.size", queueManagerDetailsSize), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "queue_managers.0.status_uri"), + resource.TestCheckResourceAttr("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "queue_managers.0.version", queueManagerDetailsVersion), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "queue_managers.0.web_console_url"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "queue_managers.0.rest_api_endpoint_url"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "queue_managers.0.administrator_api_endpoint_url"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "queue_managers.0.connection_info_uri"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "queue_managers.0.date_created"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "queue_managers.0.upgrade_available"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "queue_managers.0.available_upgrade_versions_uri"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "queue_managers.0.href"), + ), + }, + }, + }) +} + +func testAccCheckIbmMqcloudQueueManagerDataSourceConfigBasic(queueManagerDetailsServiceInstanceGuid string, queueManagerDetailsName string, queueManagerDetailsLocation string, queueManagerDetailsSize string) string { + return fmt.Sprintf(` + resource "ibm_mqcloud_queue_manager" "mqcloud_queue_manager_instance" { + service_instance_guid = "%s" + name = "%s" + location = "%s" + size = "%s" + } + + data "ibm_mqcloud_queue_manager" "mqcloud_queue_manager_instance" { + service_instance_guid = ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance.service_instance_guid + name = ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance.name + } + `, queueManagerDetailsServiceInstanceGuid, queueManagerDetailsName, queueManagerDetailsLocation, queueManagerDetailsSize) +} + +func testAccCheckIbmMqcloudQueueManagerDataSourceConfig(queueManagerDetailsServiceInstanceGuid string, queueManagerDetailsName string, queueManagerDetailsDisplayName string, queueManagerDetailsLocation string, queueManagerDetailsSize string, queueManagerDetailsVersion string) string { + return fmt.Sprintf(` + resource "ibm_mqcloud_queue_manager" "mqcloud_queue_manager_instance" { + service_instance_guid = "%s" + name = "%s" + display_name = "%s" + location = "%s" + size = "%s" + version = "%s" + } + + data "ibm_mqcloud_queue_manager" "mqcloud_queue_manager_instance" { + service_instance_guid = ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance.service_instance_guid + name = ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance.name + } + `, queueManagerDetailsServiceInstanceGuid, queueManagerDetailsName, queueManagerDetailsDisplayName, queueManagerDetailsLocation, queueManagerDetailsSize, queueManagerDetailsVersion) +} diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_truststore_certificate.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_truststore_certificate.go new file mode 100644 index 0000000000..265c2cb8b1 --- /dev/null +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_truststore_certificate.go @@ -0,0 +1,208 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package mqcloud + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/mqcloud-go-sdk/mqcloudv1" +) + +func DataSourceIbmMqcloudTruststoreCertificate() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIbmMqcloudTruststoreCertificateRead, + + Schema: map[string]*schema.Schema{ + "service_instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "The GUID that uniquely identifies the MQ on Cloud service instance.", + }, + "queue_manager_id": { + Type: schema.TypeString, + Required: true, + Description: "The id of the queue manager to retrieve its full details.", + }, + "label": { + Type: schema.TypeString, + Optional: true, + Description: "Certificate label in queue manager store.", + }, + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total count of trust store certificates.", + }, + "trust_store": { + Type: schema.TypeList, + Computed: true, + Description: "The list of trust store certificates.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Id of the certificate.", + }, + "label": { + Type: schema.TypeString, + Computed: true, + Description: "Certificate label in queue manager store.", + }, + "certificate_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of certificate.", + }, + "fingerprint_sha256": { + Type: schema.TypeString, + Computed: true, + Description: "Fingerprint SHA256.", + }, + "subject_dn": { + Type: schema.TypeString, + Computed: true, + Description: "Subject's Distinguished Name.", + }, + "subject_cn": { + Type: schema.TypeString, + Computed: true, + Description: "Subject's Common Name.", + }, + "issuer_dn": { + Type: schema.TypeString, + Computed: true, + Description: "Issuer's Distinguished Name.", + }, + "issuer_cn": { + Type: schema.TypeString, + Computed: true, + Description: "Issuer's Common Name.", + }, + "issued": { + Type: schema.TypeString, + Computed: true, + Description: "The Date the certificate was issued.", + }, + "expiry": { + Type: schema.TypeString, + Computed: true, + Description: "Expiry date for the certificate.", + }, + "trusted": { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether a certificate is trusted.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this trust store certificate.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIbmMqcloudTruststoreCertificateRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return diag.FromErr(err) + } + err = checkSIPlan(d, meta) + if err != nil { + return diag.FromErr(fmt.Errorf("Read Truststore Certificate failed %s", err)) + } + + listTrustStoreCertificatesOptions := &mqcloudv1.ListTrustStoreCertificatesOptions{} + + listTrustStoreCertificatesOptions.SetServiceInstanceGuid(d.Get("service_instance_guid").(string)) + listTrustStoreCertificatesOptions.SetQueueManagerID(d.Get("queue_manager_id").(string)) + + trustStoreCertificateDetailsCollection, response, err := mqcloudClient.ListTrustStoreCertificatesWithContext(context, listTrustStoreCertificatesOptions) + if err != nil { + log.Printf("[DEBUG] ListTrustStoreCertificatesWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("ListTrustStoreCertificatesWithContext failed %s\n%s", err, response)) + } + + // Use the provided filter argument and construct a new list with only the requested resource(s) + var matchTrustStore []mqcloudv1.TrustStoreCertificateDetails + var label string + var suppliedFilter bool + + if v, ok := d.GetOk("label"); ok { + label = v.(string) + suppliedFilter = true + for _, data := range trustStoreCertificateDetailsCollection.TrustStore { + if *data.Label == label { + matchTrustStore = append(matchTrustStore, data) + } + } + } else { + matchTrustStore = trustStoreCertificateDetailsCollection.TrustStore + } + trustStoreCertificateDetailsCollection.TrustStore = matchTrustStore + + if suppliedFilter { + if len(trustStoreCertificateDetailsCollection.TrustStore) == 0 { + return diag.FromErr(fmt.Errorf("no TrustStore found with label %s", label)) + } + d.SetId(label) + } else { + d.SetId(dataSourceIbmMqcloudTruststoreCertificateID(d)) + } + + if err = d.Set("total_count", flex.IntValue(trustStoreCertificateDetailsCollection.TotalCount)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting total_count: %s", err)) + } + + trustStore := []map[string]interface{}{} + if trustStoreCertificateDetailsCollection.TrustStore != nil { + for _, modelItem := range trustStoreCertificateDetailsCollection.TrustStore { + modelItem := modelItem + modelMap, err := dataSourceIbmMqcloudTruststoreCertificateTrustStoreCertificateDetailsToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + trustStore = append(trustStore, modelMap) + } + } + if err = d.Set("trust_store", trustStore); err != nil { + return diag.FromErr(fmt.Errorf("Error setting trust_store %s", err)) + } + + return nil +} + +// dataSourceIbmMqcloudTruststoreCertificateID returns a reasonable ID for the list. +func dataSourceIbmMqcloudTruststoreCertificateID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceIbmMqcloudTruststoreCertificateTrustStoreCertificateDetailsToMap(model *mqcloudv1.TrustStoreCertificateDetails) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = model.ID + modelMap["label"] = model.Label + modelMap["certificate_type"] = model.CertificateType + modelMap["fingerprint_sha256"] = model.FingerprintSha256 + modelMap["subject_dn"] = model.SubjectDn + modelMap["subject_cn"] = model.SubjectCn + modelMap["issuer_dn"] = model.IssuerDn + modelMap["issuer_cn"] = model.IssuerCn + modelMap["issued"] = model.Issued.String() + modelMap["expiry"] = model.Expiry.String() + modelMap["trusted"] = model.Trusted + modelMap["href"] = model.Href + return modelMap, nil +} diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_truststore_certificate_test.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_truststore_certificate_test.go new file mode 100644 index 0000000000..a4c50e196f --- /dev/null +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_truststore_certificate_test.go @@ -0,0 +1,106 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package mqcloud_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIbmMqcloudTruststoreCertificateDataSourceBasic(t *testing.T) { + trustStoreCertificateDetailsServiceInstanceGuid := acc.MqcloudInstanceID + trustStoreCertificateDetailsQueueManagerID := acc.MqcloudQueueManagerID + trustStoreCertificateDetailsLabel := fmt.Sprintf("tf_label_%d", acctest.RandIntRange(10, 100)) + trustStoreCertificateDetailsCertificateFile := acc.MqcloudTSCertFilePath + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudTruststoreCertificateDataSourceConfigBasic(trustStoreCertificateDetailsServiceInstanceGuid, trustStoreCertificateDetailsQueueManagerID, trustStoreCertificateDetailsLabel, trustStoreCertificateDetailsCertificateFile), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "service_instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "queue_manager_id"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "trust_store.#"), + resource.TestCheckResourceAttr("data.ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "trust_store.0.label", trustStoreCertificateDetailsLabel), + ), + }, + }, + }) +} + +func TestAccIbmMqcloudTruststoreCertificateDataSourceAllArgs(t *testing.T) { + trustStoreCertificateDetailsServiceInstanceGuid := acc.MqcloudInstanceID + trustStoreCertificateDetailsQueueManagerID := acc.MqcloudQueueManagerID + trustStoreCertificateDetailsLabel := fmt.Sprintf("tf_label_%d", acctest.RandIntRange(10, 100)) + trustStoreCertificateDetailsCertificateFile := acc.MqcloudTSCertFilePath + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudTruststoreCertificateDataSourceConfig(trustStoreCertificateDetailsServiceInstanceGuid, trustStoreCertificateDetailsQueueManagerID, trustStoreCertificateDetailsLabel, trustStoreCertificateDetailsCertificateFile), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "service_instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "queue_manager_id"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "label"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "total_count"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "trust_store.#"), + resource.TestCheckResourceAttr("data.ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "trust_store.0.label", trustStoreCertificateDetailsLabel), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "trust_store.0.certificate_type"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "trust_store.0.fingerprint_sha256"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "trust_store.0.subject_dn"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "trust_store.0.subject_cn"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "trust_store.0.issuer_dn"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "trust_store.0.issuer_cn"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "trust_store.0.issued"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "trust_store.0.expiry"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "trust_store.0.trusted"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "trust_store.0.href"), + ), + }, + }, + }) +} + +func testAccCheckIbmMqcloudTruststoreCertificateDataSourceConfigBasic(trustStoreCertificateDetailsServiceInstanceGuid string, trustStoreCertificateDetailsQueueManagerID string, trustStoreCertificateDetailsLabel string, trustStoreCertificateDetailsCertificateFile string) string { + return fmt.Sprintf(` + resource "ibm_mqcloud_truststore_certificate" "mqcloud_truststore_certificate_instance" { + service_instance_guid = "%s" + queue_manager_id = "%s" + label = "%s" + certificate_file = "%s" + } + + data "ibm_mqcloud_truststore_certificate" "mqcloud_truststore_certificate_instance" { + service_instance_guid = ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance.service_instance_guid + queue_manager_id = ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance.queue_manager_id + label = ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance.label + } + `, trustStoreCertificateDetailsServiceInstanceGuid, trustStoreCertificateDetailsQueueManagerID, trustStoreCertificateDetailsLabel, trustStoreCertificateDetailsCertificateFile) +} + +func testAccCheckIbmMqcloudTruststoreCertificateDataSourceConfig(trustStoreCertificateDetailsServiceInstanceGuid string, trustStoreCertificateDetailsQueueManagerID string, trustStoreCertificateDetailsLabel string, trustStoreCertificateDetailsCertificateFile string) string { + return fmt.Sprintf(` + resource "ibm_mqcloud_truststore_certificate" "mqcloud_truststore_certificate_instance" { + service_instance_guid = "%s" + queue_manager_id = "%s" + label = "%s" + certificate_file = "%s" + } + + data "ibm_mqcloud_truststore_certificate" "mqcloud_truststore_certificate_instance" { + service_instance_guid = ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance.service_instance_guid + queue_manager_id = ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance.queue_manager_id + label = ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance.label + } + `, trustStoreCertificateDetailsServiceInstanceGuid, trustStoreCertificateDetailsQueueManagerID, trustStoreCertificateDetailsLabel, trustStoreCertificateDetailsCertificateFile) +} diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_user.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_user.go new file mode 100644 index 0000000000..259aefa17d --- /dev/null +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_user.go @@ -0,0 +1,166 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package mqcloud + +import ( + "context" + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/mqcloud-go-sdk/mqcloudv1" +) + +func DataSourceIbmMqcloudUser() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIbmMqcloudUserRead, + + Schema: map[string]*schema.Schema{ + "service_instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "The GUID that uniquely identifies the MQ on Cloud service instance.", + }, + "name": { + Type: schema.TypeString, + Optional: true, + Description: "The shortname of the user that will be used as the IBM MQ administrator in interactions with a queue manager for this service instance.", + }, + "users": { + Type: schema.TypeList, + Computed: true, + Description: "List of users.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the user which was allocated on creation, and can be used for delete calls.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The shortname of the user that will be used as the IBM MQ administrator in interactions with a queue manager for this service instance.", + }, + "email": { + Type: schema.TypeString, + Computed: true, + Description: "The email of the user.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for the user details.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIbmMqcloudUserRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return diag.FromErr(err) + } + + err = checkSIPlan(d, meta) + if err != nil { + return diag.FromErr(fmt.Errorf("Read User failed %s", err)) + } + + serviceInstanceGuid := d.Get("service_instance_guid").(string) + + // Support for pagination + offset := int64(0) + limit := int64(25) + allItems := []mqcloudv1.UserDetails{} + + for { + listUsersOptions := &mqcloudv1.ListUsersOptions{ + ServiceInstanceGuid: &serviceInstanceGuid, + Limit: &limit, + Offset: &offset, + } + + result, response, err := mqcloudClient.ListUsersWithContext(context, listUsersOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error Getting Users %s\n%s", err, response)) + } + if result == nil { + return diag.FromErr(fmt.Errorf("List Users returned nil")) + } + + allItems = append(allItems, result.Users...) + + // Check if the number of returned records is less than the limit + if int64(len(result.Users)) < limit { + break + } + + offset += limit + } + + // Use the provided filter argument and construct a new list with only the requested resource(s) + var matchUsers []mqcloudv1.UserDetails + var name string + var suppliedFilter bool + + if v, ok := d.GetOk("name"); ok { + name = v.(string) + suppliedFilter = true + for _, data := range allItems { + if *data.Name == name { + matchUsers = append(matchUsers, data) + } + } + } else { + matchUsers = allItems + } + + allItems = matchUsers + + if suppliedFilter { + if len(allItems) == 0 { + return diag.FromErr(fmt.Errorf("No Users found with name %s", name)) + } + d.SetId(name) + } else { + d.SetId(dataSourceIbmMqcloudUserID(d)) + } + + mapSlice := []map[string]interface{}{} + for _, modelItem := range allItems { + modelItem := modelItem + modelMap, err := dataSourceIbmMqcloudUserUserDetailsToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + mapSlice = append(mapSlice, modelMap) + } + + if err = d.Set("users", mapSlice); err != nil { + return diag.FromErr(fmt.Errorf("Error setting users %s", err)) + } + + return nil +} + +// dataSourceIbmMqcloudUserID returns a reasonable ID for the list. +func dataSourceIbmMqcloudUserID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func dataSourceIbmMqcloudUserUserDetailsToMap(model *mqcloudv1.UserDetails) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = model.ID + modelMap["name"] = model.Name + modelMap["email"] = model.Email + modelMap["href"] = model.Href + return modelMap, nil +} diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_user_test.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_user_test.go new file mode 100644 index 0000000000..eb3491817e --- /dev/null +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_user_test.go @@ -0,0 +1,93 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package mqcloud_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIbmMqcloudUserDataSourceBasic(t *testing.T) { + userDetailsServiceInstanceGuid := acc.MqcloudInstanceID + userDetailsName := fmt.Sprintf("tfname%d", acctest.RandIntRange(10, 100)) + userDetailsEmail := fmt.Sprintf("tfemail%d@ibm.com", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudUserDataSourceConfigBasic(userDetailsServiceInstanceGuid, userDetailsName, userDetailsEmail), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_user.mqcloud_user_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_user.mqcloud_user_instance", "service_instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_user.mqcloud_user_instance", "users.#"), + resource.TestCheckResourceAttr("data.ibm_mqcloud_user.mqcloud_user_instance", "users.0.name", userDetailsName), + resource.TestCheckResourceAttr("data.ibm_mqcloud_user.mqcloud_user_instance", "users.0.email", userDetailsEmail), + ), + }, + }, + }) +} + +func TestAccIbmMqcloudUserDataSourceAllArgs(t *testing.T) { + userDetailsServiceInstanceGuid := acc.MqcloudInstanceID + userDetailsName := fmt.Sprintf("tfname%d", acctest.RandIntRange(10, 100)) + userDetailsEmail := fmt.Sprintf("tfemail%d@ibm.com", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudUserDataSourceConfig(userDetailsServiceInstanceGuid, userDetailsName, userDetailsEmail), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_user.mqcloud_user_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_user.mqcloud_user_instance", "service_instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_user.mqcloud_user_instance", "name"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_user.mqcloud_user_instance", "users.#"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_user.mqcloud_user_instance", "users.0.id"), + resource.TestCheckResourceAttr("data.ibm_mqcloud_user.mqcloud_user_instance", "users.0.name", userDetailsName), + resource.TestCheckResourceAttr("data.ibm_mqcloud_user.mqcloud_user_instance", "users.0.email", userDetailsEmail), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_user.mqcloud_user_instance", "users.0.href"), + ), + }, + }, + }) +} + +func testAccCheckIbmMqcloudUserDataSourceConfigBasic(userDetailsServiceInstanceGuid string, userDetailsName string, userDetailsEmail string) string { + return fmt.Sprintf(` + resource "ibm_mqcloud_user" "mqcloud_user_instance" { + service_instance_guid = "%s" + name = "%s" + email = "%s" + } + + data "ibm_mqcloud_user" "mqcloud_user_instance" { + service_instance_guid = ibm_mqcloud_user.mqcloud_user_instance.service_instance_guid + name = ibm_mqcloud_user.mqcloud_user_instance.name + } + `, userDetailsServiceInstanceGuid, userDetailsName, userDetailsEmail) +} + +func testAccCheckIbmMqcloudUserDataSourceConfig(userDetailsServiceInstanceGuid string, userDetailsName string, userDetailsEmail string) string { + return fmt.Sprintf(` + resource "ibm_mqcloud_user" "mqcloud_user_instance" { + service_instance_guid = "%s" + name = "%s" + email = "%s" + } + + data "ibm_mqcloud_user" "mqcloud_user_instance" { + service_instance_guid = ibm_mqcloud_user.mqcloud_user_instance.service_instance_guid + name = ibm_mqcloud_user.mqcloud_user_instance.name + } + `, userDetailsServiceInstanceGuid, userDetailsName, userDetailsEmail) +} diff --git a/ibm/service/mqcloud/resource_ibm_mqcloud_application.go b/ibm/service/mqcloud/resource_ibm_mqcloud_application.go new file mode 100644 index 0000000000..6b317ad242 --- /dev/null +++ b/ibm/service/mqcloud/resource_ibm_mqcloud_application.go @@ -0,0 +1,188 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package mqcloud + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/mqcloud-go-sdk/mqcloudv1" +) + +func ResourceIbmMqcloudApplication() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIbmMqcloudApplicationCreate, + ReadContext: resourceIbmMqcloudApplicationRead, + DeleteContext: resourceIbmMqcloudApplicationDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "service_instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_mqcloud_application", "service_instance_guid"), + Description: "The GUID that uniquely identifies the MQ on Cloud service instance.", + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_mqcloud_application", "name"), + Description: "The name of the application - conforming to MQ rules.", + }, + "create_api_key_uri": { + Type: schema.TypeString, + Computed: true, + Description: "The URI to create a new apikey for the application.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this application.", + }, + "application_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the application which was allocated on creation, and can be used for delete calls.", + }, + }, + } +} + +func ResourceIbmMqcloudApplicationValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "service_instance_guid", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-z][-a-z0-9]*$`, + MinValueLength: 1, + MaxValueLength: 12, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_mqcloud_application", Schema: validateSchema} + return &resourceValidator +} + +func resourceIbmMqcloudApplicationCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return diag.FromErr(err) + } + err = checkSIPlan(d, meta) + if err != nil { + return diag.FromErr(fmt.Errorf("Create Application failed %s", err)) + } + + createApplicationOptions := &mqcloudv1.CreateApplicationOptions{} + + createApplicationOptions.SetServiceInstanceGuid(d.Get("service_instance_guid").(string)) + createApplicationOptions.SetName(d.Get("name").(string)) + + applicationCreated, response, err := mqcloudClient.CreateApplicationWithContext(context, createApplicationOptions) + if err != nil { + log.Printf("[DEBUG] CreateApplicationWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateApplicationWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createApplicationOptions.ServiceInstanceGuid, *applicationCreated.ID)) + + return resourceIbmMqcloudApplicationRead(context, d, meta) +} + +func resourceIbmMqcloudApplicationRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return diag.FromErr(err) + } + + getApplicationOptions := &mqcloudv1.GetApplicationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getApplicationOptions.SetServiceInstanceGuid(parts[0]) + getApplicationOptions.SetApplicationID(parts[1]) + + applicationDetails, response, err := mqcloudClient.GetApplicationWithContext(context, getApplicationOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetApplicationWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetApplicationWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("name", applicationDetails.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("service_instance_guid", parts[0]); err != nil { + return diag.FromErr(fmt.Errorf("Error setting service instance guid: %s", err)) + } + if err = d.Set("create_api_key_uri", applicationDetails.CreateApiKeyURI); err != nil { + return diag.FromErr(fmt.Errorf("Error setting create_api_key_uri: %s", err)) + } + if err = d.Set("href", applicationDetails.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + if err = d.Set("application_id", applicationDetails.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting application_id: %s", err)) + } + + return nil +} + +func resourceIbmMqcloudApplicationDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return diag.FromErr(err) + } + err = checkSIPlan(d, meta) + if err != nil { + return diag.FromErr(fmt.Errorf("Delete Application failed %s", err)) + } + + deleteApplicationOptions := &mqcloudv1.DeleteApplicationOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteApplicationOptions.SetServiceInstanceGuid(parts[0]) + deleteApplicationOptions.SetApplicationID(parts[1]) + + response, err := mqcloudClient.DeleteApplicationWithContext(context, deleteApplicationOptions) + if err != nil { + log.Printf("[DEBUG] DeleteApplicationWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteApplicationWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/mqcloud/resource_ibm_mqcloud_application_test.go b/ibm/service/mqcloud/resource_ibm_mqcloud_application_test.go new file mode 100644 index 0000000000..b780d789d1 --- /dev/null +++ b/ibm/service/mqcloud/resource_ibm_mqcloud_application_test.go @@ -0,0 +1,150 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package mqcloud_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/mqcloud-go-sdk/mqcloudv1" +) + +func TestAccIbmMqcloudApplicationBasic(t *testing.T) { + var conf mqcloudv1.ApplicationDetails + serviceInstanceGuid := acc.MqcloudInstanceID + name := "appbasic" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmMqcloudApplicationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudApplicationConfigBasic(serviceInstanceGuid, name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmMqcloudApplicationExists("ibm_mqcloud_application.mqcloud_application_instance", conf), + resource.TestCheckResourceAttr("ibm_mqcloud_application.mqcloud_application_instance", "service_instance_guid", serviceInstanceGuid), + resource.TestCheckResourceAttr("ibm_mqcloud_application.mqcloud_application_instance", "name", name), + ), + }, + }, + }) +} + +func TestAccIbmMqcloudApplicationAllArgs(t *testing.T) { + var conf mqcloudv1.ApplicationDetails + serviceInstanceGuid := acc.MqcloudInstanceID + name := "appallargs" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmMqcloudApplicationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudApplicationConfig(serviceInstanceGuid, name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmMqcloudApplicationExists("ibm_mqcloud_application.mqcloud_application_instance", conf), + resource.TestCheckResourceAttr("ibm_mqcloud_application.mqcloud_application_instance", "service_instance_guid", serviceInstanceGuid), + resource.TestCheckResourceAttr("ibm_mqcloud_application.mqcloud_application_instance", "name", name), + ), + }, + { + ResourceName: "ibm_mqcloud_application.mqcloud_application_instance", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIbmMqcloudApplicationConfigBasic(serviceInstanceGuid string, name string) string { + return fmt.Sprintf(` + resource "ibm_mqcloud_application" "mqcloud_application_instance" { + service_instance_guid = "%s" + name = "%s" + } + `, serviceInstanceGuid, name) +} + +func testAccCheckIbmMqcloudApplicationConfig(serviceInstanceGuid string, name string) string { + return fmt.Sprintf(` + + resource "ibm_mqcloud_application" "mqcloud_application_instance" { + service_instance_guid = "%s" + name = "%s" + } + `, serviceInstanceGuid, name) +} + +func testAccCheckIbmMqcloudApplicationExists(n string, obj mqcloudv1.ApplicationDetails) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + mqcloudClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MqcloudV1() + if err != nil { + return err + } + + getApplicationOptions := &mqcloudv1.GetApplicationOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getApplicationOptions.SetServiceInstanceGuid(parts[0]) + getApplicationOptions.SetApplicationID(parts[1]) + + applicationDetails, _, err := mqcloudClient.GetApplication(getApplicationOptions) + if err != nil { + return err + } + + obj = *applicationDetails + return nil + } +} + +func testAccCheckIbmMqcloudApplicationDestroy(s *terraform.State) error { + mqcloudClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MqcloudV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_mqcloud_application" { + continue + } + + getApplicationOptions := &mqcloudv1.GetApplicationOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getApplicationOptions.SetServiceInstanceGuid(parts[0]) + getApplicationOptions.SetApplicationID(parts[1]) + + // Try to find the key + _, response, err := mqcloudClient.GetApplication(getApplicationOptions) + + if err == nil { + return fmt.Errorf("mqcloud_application still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for mqcloud_application (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/mqcloud/resource_ibm_mqcloud_keystore_certificate.go b/ibm/service/mqcloud/resource_ibm_mqcloud_keystore_certificate.go new file mode 100644 index 0000000000..859d0aa5cc --- /dev/null +++ b/ibm/service/mqcloud/resource_ibm_mqcloud_keystore_certificate.go @@ -0,0 +1,314 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package mqcloud + +import ( + "context" + "fmt" + "io" + "log" + "os" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/mqcloud-go-sdk/mqcloudv1" +) + +func ResourceIbmMqcloudKeystoreCertificate() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIbmMqcloudKeystoreCertificateCreate, + ReadContext: resourceIbmMqcloudKeystoreCertificateRead, + DeleteContext: resourceIbmMqcloudKeystoreCertificateDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "service_instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_mqcloud_keystore_certificate", "service_instance_guid"), + Description: "The GUID that uniquely identifies the MQ on Cloud service instance.", + }, + "queue_manager_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_mqcloud_keystore_certificate", "queue_manager_id"), + Description: "The id of the queue manager to retrieve its full details.", + }, + "label": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_mqcloud_keystore_certificate", "label"), + Description: "Certificate label in queue manager store.", + }, + "certificate_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of certificate.", + }, + "fingerprint_sha256": { + Type: schema.TypeString, + Computed: true, + Description: "Fingerprint SHA256.", + }, + "subject_dn": { + Type: schema.TypeString, + Computed: true, + Description: "Subject's Distinguished Name.", + }, + "subject_cn": { + Type: schema.TypeString, + Computed: true, + Description: "Subject's Common Name.", + }, + "issuer_dn": { + Type: schema.TypeString, + Computed: true, + Description: "Issuer's Distinguished Name.", + }, + "issuer_cn": { + Type: schema.TypeString, + Computed: true, + Description: "Issuer's Common Name.", + }, + "issued": { + Type: schema.TypeString, + Computed: true, + Description: "Date certificate was issued.", + }, + "expiry": { + Type: schema.TypeString, + Computed: true, + Description: "Expiry date for the certificate.", + }, + "is_default": { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether it is the queue manager's default certificate.", + }, + "dns_names_total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total count of dns names.", + }, + "dns_names": { + Type: schema.TypeList, + Computed: true, + Description: "The list of DNS names.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this key store certificate.", + }, + "certificate_id": { + Type: schema.TypeString, + Computed: true, + Description: "ID of the certificate.", + }, + "certificate_file": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The filename and path of the certificate to be uploaded.", + }, + }, + } +} + +func ResourceIbmMqcloudKeystoreCertificateValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "service_instance_guid", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "queue_manager_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[0-9a-fA-F]{32}$`, + MinValueLength: 32, + MaxValueLength: 32, + }, + validate.ValidateSchema{ + Identifier: "label", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-zA-Z0-9_.]*$`, + MinValueLength: 1, + MaxValueLength: 64, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_mqcloud_keystore_certificate", Schema: validateSchema} + return &resourceValidator +} + +func resourceIbmMqcloudKeystoreCertificateCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return diag.FromErr(err) + } + err = checkSIPlan(d, meta) + if err != nil { + return diag.FromErr(fmt.Errorf("Create Keystore Certificate failed %s", err)) + } + createKeyStorePemCertificateOptions := &mqcloudv1.CreateKeyStorePemCertificateOptions{} + + createKeyStorePemCertificateOptions.SetServiceInstanceGuid(d.Get("service_instance_guid").(string)) + createKeyStorePemCertificateOptions.SetQueueManagerID(d.Get("queue_manager_id").(string)) + createKeyStorePemCertificateOptions.SetLabel(d.Get("label").(string)) + //Custom code to read certs and pass to SDK + certBytes, err := os.ReadFile(d.Get("certificate_file").(string)) // just pass the file name + if err != nil { + fmt.Print(err) + } + certString := string(certBytes) // convert content to a 'string' + rc := io.NopCloser(strings.NewReader(certString)) + // certificateFileModel, err := resourceIbmMqcloudKeystoreCertificateMapToio.ReadCloser(d.Get("certificate_file.0").(map[string]interface{})) + // if err != nil { + // return diag.FromErr(err) + // } + createKeyStorePemCertificateOptions.SetCertificateFile(rc) + + keyStoreCertificateDetails, response, err := mqcloudClient.CreateKeyStorePemCertificateWithContext(context, createKeyStorePemCertificateOptions) + if err != nil { + log.Printf("[DEBUG] CreateKeyStorePemCertificateWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateKeyStorePemCertificateWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s/%s", *createKeyStorePemCertificateOptions.ServiceInstanceGuid, *createKeyStorePemCertificateOptions.QueueManagerID, *keyStoreCertificateDetails.ID)) + + return resourceIbmMqcloudKeystoreCertificateRead(context, d, meta) +} + +func resourceIbmMqcloudKeystoreCertificateRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return diag.FromErr(err) + } + + getKeyStoreCertificateOptions := &mqcloudv1.GetKeyStoreCertificateOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getKeyStoreCertificateOptions.SetServiceInstanceGuid(parts[0]) + getKeyStoreCertificateOptions.SetQueueManagerID(parts[1]) + getKeyStoreCertificateOptions.SetCertificateID(parts[2]) + + keyStoreCertificateDetails, response, err := mqcloudClient.GetKeyStoreCertificateWithContext(context, getKeyStoreCertificateOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetKeyStoreCertificateWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetKeyStoreCertificateWithContext failed %s\n%s", err, response)) + } + if err = d.Set("service_instance_guid", parts[0]); err != nil { + return diag.FromErr(fmt.Errorf("Error setting service_instance_guid: %s", err)) + } + if err = d.Set("queue_manager_id", parts[1]); err != nil { + return diag.FromErr(fmt.Errorf("Error setting queue_manager_id: %s", err)) + } + downloadCertificatePath := "./certificates/keystore/" + *keyStoreCertificateDetails.Label + ".pem" + if err = d.Set("certificate_file", downloadCertificatePath); err != nil { + return diag.FromErr(fmt.Errorf("Error setting certificate_file: %s", err)) + } + if err = d.Set("label", keyStoreCertificateDetails.Label); err != nil { + return diag.FromErr(fmt.Errorf("Error setting label: %s", err)) + } + if err = d.Set("certificate_type", keyStoreCertificateDetails.CertificateType); err != nil { + return diag.FromErr(fmt.Errorf("Error setting certificate_type: %s", err)) + } + if err = d.Set("fingerprint_sha256", keyStoreCertificateDetails.FingerprintSha256); err != nil { + return diag.FromErr(fmt.Errorf("Error setting fingerprint_sha256: %s", err)) + } + if err = d.Set("subject_dn", keyStoreCertificateDetails.SubjectDn); err != nil { + return diag.FromErr(fmt.Errorf("Error setting subject_dn: %s", err)) + } + if err = d.Set("subject_cn", keyStoreCertificateDetails.SubjectCn); err != nil { + return diag.FromErr(fmt.Errorf("Error setting subject_cn: %s", err)) + } + if err = d.Set("issuer_dn", keyStoreCertificateDetails.IssuerDn); err != nil { + return diag.FromErr(fmt.Errorf("Error setting issuer_dn: %s", err)) + } + if err = d.Set("issuer_cn", keyStoreCertificateDetails.IssuerCn); err != nil { + return diag.FromErr(fmt.Errorf("Error setting issuer_cn: %s", err)) + } + if err = d.Set("issued", flex.DateTimeToString(keyStoreCertificateDetails.Issued)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting issued: %s", err)) + } + if err = d.Set("expiry", flex.DateTimeToString(keyStoreCertificateDetails.Expiry)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting expiry: %s", err)) + } + if err = d.Set("is_default", keyStoreCertificateDetails.IsDefault); err != nil { + return diag.FromErr(fmt.Errorf("Error setting is_default: %s", err)) + } + if err = d.Set("dns_names_total_count", flex.IntValue(keyStoreCertificateDetails.DnsNamesTotalCount)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting dns_names_total_count: %s", err)) + } + if err = d.Set("dns_names", keyStoreCertificateDetails.DnsNames); err != nil { + return diag.FromErr(fmt.Errorf("Error setting dns_names: %s", err)) + } + if err = d.Set("href", keyStoreCertificateDetails.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + if err = d.Set("certificate_id", keyStoreCertificateDetails.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting certificate_id: %s", err)) + } + + return nil +} + +func resourceIbmMqcloudKeystoreCertificateDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return diag.FromErr(err) + } + err = checkSIPlan(d, meta) + if err != nil { + return diag.FromErr(fmt.Errorf("Delete Keystore Certificate failed %s", err)) + } + + deleteKeyStoreCertificateOptions := &mqcloudv1.DeleteKeyStoreCertificateOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteKeyStoreCertificateOptions.SetServiceInstanceGuid(parts[0]) + deleteKeyStoreCertificateOptions.SetQueueManagerID(parts[1]) + deleteKeyStoreCertificateOptions.SetCertificateID(parts[2]) + + response, err := mqcloudClient.DeleteKeyStoreCertificateWithContext(context, deleteKeyStoreCertificateOptions) + if err != nil { + log.Printf("[DEBUG] DeleteKeyStoreCertificateWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteKeyStoreCertificateWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/mqcloud/resource_ibm_mqcloud_keystore_certificate_test.go b/ibm/service/mqcloud/resource_ibm_mqcloud_keystore_certificate_test.go new file mode 100644 index 0000000000..5041c8ed77 --- /dev/null +++ b/ibm/service/mqcloud/resource_ibm_mqcloud_keystore_certificate_test.go @@ -0,0 +1,163 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package mqcloud_test + +import ( + "fmt" + "testing" + + "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" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/mqcloud-go-sdk/mqcloudv1" +) + +func TestAccIbmMqcloudKeystoreCertificateBasic(t *testing.T) { + var conf mqcloudv1.KeyStoreCertificateDetails + serviceInstanceGuid := acc.MqcloudInstanceID + queueManagerID := acc.MqcloudQueueManagerID + label := fmt.Sprintf("tf_label_%d", acctest.RandIntRange(10, 100)) + certificateFile := acc.MqcloudKSCertFilePath + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmMqcloudKeystoreCertificateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudKeystoreCertificateConfigBasic(serviceInstanceGuid, queueManagerID, label, certificateFile), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmMqcloudKeystoreCertificateExists("ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", conf), + resource.TestCheckResourceAttr("ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "service_instance_guid", serviceInstanceGuid), + resource.TestCheckResourceAttr("ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "queue_manager_id", queueManagerID), + resource.TestCheckResourceAttr("ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "label", label), + ), + }, + }, + }) +} + +func TestAccIbmMqcloudKeystoreCertificateAllArgs(t *testing.T) { + var conf mqcloudv1.KeyStoreCertificateDetails + serviceInstanceGuid := acc.MqcloudInstanceID + queueManagerID := acc.MqcloudQueueManagerID + label := fmt.Sprintf("tf_label_%d", acctest.RandIntRange(10, 100)) + certificateFile := acc.MqcloudKSCertFilePath + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmMqcloudKeystoreCertificateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudKeystoreCertificateConfig(serviceInstanceGuid, queueManagerID, label, certificateFile), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmMqcloudKeystoreCertificateExists("ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", conf), + resource.TestCheckResourceAttr("ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "service_instance_guid", serviceInstanceGuid), + resource.TestCheckResourceAttr("ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "queue_manager_id", queueManagerID), + resource.TestCheckResourceAttr("ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", "label", label), + ), + }, + { + ResourceName: "ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIbmMqcloudKeystoreCertificateConfigBasic(serviceInstanceGuid string, queueManagerID string, label string, certificateFile string) string { + return fmt.Sprintf(` + resource "ibm_mqcloud_keystore_certificate" "mqcloud_keystore_certificate_instance" { + service_instance_guid = "%s" + queue_manager_id = "%s" + label = "%s" + certificate_file = "%s" + } + `, serviceInstanceGuid, queueManagerID, label, certificateFile) +} + +func testAccCheckIbmMqcloudKeystoreCertificateConfig(serviceInstanceGuid string, queueManagerID string, label string, certificateFile string) string { + return fmt.Sprintf(` + + resource "ibm_mqcloud_keystore_certificate" "mqcloud_keystore_certificate_instance" { + service_instance_guid = "%s" + queue_manager_id = "%s" + label = "%s" + certificate_file = "%s" + } + `, serviceInstanceGuid, queueManagerID, label, certificateFile) +} + +func testAccCheckIbmMqcloudKeystoreCertificateExists(n string, obj mqcloudv1.KeyStoreCertificateDetails) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + mqcloudClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MqcloudV1() + if err != nil { + return err + } + + getKeyStoreCertificateOptions := &mqcloudv1.GetKeyStoreCertificateOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getKeyStoreCertificateOptions.SetServiceInstanceGuid(parts[0]) + getKeyStoreCertificateOptions.SetQueueManagerID(parts[1]) + getKeyStoreCertificateOptions.SetCertificateID(parts[2]) + + keyStoreCertificateDetails, _, err := mqcloudClient.GetKeyStoreCertificate(getKeyStoreCertificateOptions) + if err != nil { + return err + } + + obj = *keyStoreCertificateDetails + return nil + } +} + +func testAccCheckIbmMqcloudKeystoreCertificateDestroy(s *terraform.State) error { + mqcloudClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MqcloudV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_mqcloud_keystore_certificate" { + continue + } + + getKeyStoreCertificateOptions := &mqcloudv1.GetKeyStoreCertificateOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getKeyStoreCertificateOptions.SetServiceInstanceGuid(parts[0]) + getKeyStoreCertificateOptions.SetQueueManagerID(parts[1]) + getKeyStoreCertificateOptions.SetCertificateID(parts[2]) + + // Try to find the key + _, response, err := mqcloudClient.GetKeyStoreCertificate(getKeyStoreCertificateOptions) + + if err == nil { + return fmt.Errorf("mqcloud_keystore_certificate still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for mqcloud_keystore_certificate (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/mqcloud/resource_ibm_mqcloud_queue_manager.go b/ibm/service/mqcloud/resource_ibm_mqcloud_queue_manager.go new file mode 100644 index 0000000000..a94f6fa5c9 --- /dev/null +++ b/ibm/service/mqcloud/resource_ibm_mqcloud_queue_manager.go @@ -0,0 +1,415 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package mqcloud + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/mqcloud-go-sdk/mqcloudv1" +) + +func ResourceIbmMqcloudQueueManager() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIbmMqcloudQueueManagerCreate, + ReadContext: resourceIbmMqcloudQueueManagerRead, + UpdateContext: resourceIbmMqcloudQueueManagerUpdate, + DeleteContext: resourceIbmMqcloudQueueManagerDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "service_instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_mqcloud_queue_manager", "service_instance_guid"), + Description: "The GUID that uniquely identifies the MQ on Cloud service instance.", + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_mqcloud_queue_manager", "name"), + Description: "A queue manager name conforming to MQ restrictions.", + }, + "display_name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_mqcloud_queue_manager", "display_name"), + Description: "A displayable name for the queue manager - limited only in length.", + }, + "location": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_mqcloud_queue_manager", "location"), + Description: "The locations in which the queue manager could be deployed.", + }, + "size": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_mqcloud_queue_manager", "size"), + Description: "The queue manager sizes of deployment available. Deployment of lite queue managers for aws_us_east_1 and aws_eu_west_1 locations is not available.", + }, + "version": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_mqcloud_queue_manager", "version"), + Description: "The MQ version of the queue manager.", + }, + "status_uri": { + Type: schema.TypeString, + Computed: true, + Description: "A reference uri to get deployment status of the queue manager.", + }, + "web_console_url": { + Type: schema.TypeString, + Computed: true, + Description: "The url through which to access the web console for this queue manager.", + }, + "rest_api_endpoint_url": { + Type: schema.TypeString, + Computed: true, + Description: "The url through which to access REST APIs for this queue manager.", + }, + "administrator_api_endpoint_url": { + Type: schema.TypeString, + Computed: true, + Description: "The url through which to access the Admin REST APIs for this queue manager.", + }, + "connection_info_uri": { + Type: schema.TypeString, + Computed: true, + Description: "The uri through which the CDDT for this queue manager can be obtained.", + }, + "date_created": { + Type: schema.TypeString, + Computed: true, + Description: "RFC3339 formatted UTC date for when the queue manager was created.", + }, + "upgrade_available": { + Type: schema.TypeBool, + Computed: true, + Description: "Describes whether an upgrade is available for this queue manager.", + }, + "available_upgrade_versions_uri": { + Type: schema.TypeString, + Computed: true, + Description: "The uri through which the available versions to upgrade to can be found for this queue manager.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this queue manager.", + }, + "queue_manager_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the queue manager which was allocated on creation, and can be used for delete calls.", + }, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(15 * time.Minute), + Delete: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(5 * time.Minute), + }, + } +} + +func ResourceIbmMqcloudQueueManagerValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "service_instance_guid", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-zA-Z0-9_.]*$`, + MinValueLength: 1, + MaxValueLength: 48, + }, + validate.ValidateSchema{ + Identifier: "display_name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^.*$`, + MinValueLength: 0, + MaxValueLength: 150, + }, + validate.ValidateSchema{ + Identifier: "location", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^([^[:ascii:]]|[a-zA-Z0-9-._: ])+$`, + MinValueLength: 2, + MaxValueLength: 150, + }, + validate.ValidateSchema{ + Identifier: "size", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "large, lite, medium, small, xsmall", + }, + validate.ValidateSchema{ + Identifier: "version", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[0-9]+.[0-9]+.[0-9]+_[0-9]+$`, + MinValueLength: 7, + MaxValueLength: 15, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_mqcloud_queue_manager", Schema: validateSchema} + return &resourceValidator +} + +func resourceIbmMqcloudQueueManagerCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return diag.FromErr(err) + } + + err = checkSIPlan(d, meta) + if err != nil { + return diag.FromErr(fmt.Errorf("Create Queue Manager failed %s", err)) + } + + createQueueManagerOptions := &mqcloudv1.CreateQueueManagerOptions{} + + createQueueManagerOptions.SetServiceInstanceGuid(d.Get("service_instance_guid").(string)) + createQueueManagerOptions.SetName(d.Get("name").(string)) + createQueueManagerOptions.SetLocation(d.Get("location").(string)) + createQueueManagerOptions.SetSize(d.Get("size").(string)) + if _, ok := d.GetOk("display_name"); ok { + createQueueManagerOptions.SetDisplayName(d.Get("display_name").(string)) + } + if _, ok := d.GetOk("version"); ok { + createQueueManagerOptions.SetVersion(d.Get("version").(string)) + } + + queueManagerTaskStatus, response, err := mqcloudClient.CreateQueueManagerWithContext(context, createQueueManagerOptions) + if err != nil { + log.Printf("[DEBUG] CreateQueueManagerWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateQueueManagerWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createQueueManagerOptions.ServiceInstanceGuid, *queueManagerTaskStatus.QueueManagerID)) + if waitForQmStatus { + _, err = waitForQmStatusUpdate(context, d, meta) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error waiting for Queue Manager (%s) to be in running state: %s", *queueManagerTaskStatus.QueueManagerID, err)) + } + } + d.SetId(fmt.Sprintf("%s/%s", *createQueueManagerOptions.ServiceInstanceGuid, *queueManagerTaskStatus.QueueManagerID)) + + return resourceIbmMqcloudQueueManagerRead(context, d, meta) +} + +func resourceIbmMqcloudQueueManagerRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return diag.FromErr(err) + } + + getQueueManagerOptions := &mqcloudv1.GetQueueManagerOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getQueueManagerOptions.SetServiceInstanceGuid(parts[0]) + getQueueManagerOptions.SetQueueManagerID(parts[1]) + + var queueManagerDetails *mqcloudv1.QueueManagerDetails + var response *core.DetailedResponse + + err = resource.RetryContext(context, 10*time.Second, func() *resource.RetryError { + queueManagerDetails, response, err = mqcloudClient.GetQueueManagerWithContext(context, getQueueManagerOptions) + if err != nil || response == nil { + if response.StatusCode == 404 { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetQueueManagerWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetQueueManagerWithContext failed %s\n%s", err, response)) + } + + if err = d.Set("service_instance_guid", parts[0]); err != nil { + return diag.FromErr(fmt.Errorf("Error setting service_instance_guid: %s", err)) + } + if err = d.Set("name", queueManagerDetails.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if !core.IsNil(queueManagerDetails.DisplayName) { + if err = d.Set("display_name", queueManagerDetails.DisplayName); err != nil { + return diag.FromErr(fmt.Errorf("Error setting display_name: %s", err)) + } + } + if err = d.Set("location", queueManagerDetails.Location); err != nil { + return diag.FromErr(fmt.Errorf("Error setting location: %s", err)) + } + if err = d.Set("size", queueManagerDetails.Size); err != nil { + return diag.FromErr(fmt.Errorf("Error setting size: %s", err)) + } + if !core.IsNil(queueManagerDetails.Version) { + if err = d.Set("version", queueManagerDetails.Version); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version: %s", err)) + } + } + if err = d.Set("status_uri", queueManagerDetails.StatusURI); err != nil { + return diag.FromErr(fmt.Errorf("Error setting status_uri: %s", err)) + } + if err = d.Set("web_console_url", queueManagerDetails.WebConsoleURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting web_console_url: %s", err)) + } + if err = d.Set("rest_api_endpoint_url", queueManagerDetails.RestApiEndpointURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting rest_api_endpoint_url: %s", err)) + } + if err = d.Set("administrator_api_endpoint_url", queueManagerDetails.AdministratorApiEndpointURL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting administrator_api_endpoint_url: %s", err)) + } + if err = d.Set("connection_info_uri", queueManagerDetails.ConnectionInfoURI); err != nil { + return diag.FromErr(fmt.Errorf("Error setting connection_info_uri: %s", err)) + } + if err = d.Set("date_created", flex.DateTimeToString(queueManagerDetails.DateCreated)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting date_created: %s", err)) + } + if err = d.Set("upgrade_available", queueManagerDetails.UpgradeAvailable); err != nil { + return diag.FromErr(fmt.Errorf("Error setting upgrade_available: %s", err)) + } + if err = d.Set("available_upgrade_versions_uri", queueManagerDetails.AvailableUpgradeVersionsURI); err != nil { + return diag.FromErr(fmt.Errorf("Error setting available_upgrade_versions_uri: %s", err)) + } + if err = d.Set("href", queueManagerDetails.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + if err = d.Set("queue_manager_id", queueManagerDetails.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting queue_manager_id: %s", err)) + } + + return nil +} + +func resourceIbmMqcloudQueueManagerUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return diag.FromErr(err) + } + + err = checkSIPlan(d, meta) + if err != nil { + return diag.FromErr(fmt.Errorf("Update Queue Manager failed %s", err)) + } + + setQueueManagerVersionOptions := &mqcloudv1.SetQueueManagerVersionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + setQueueManagerVersionOptions.SetServiceInstanceGuid(parts[0]) + setQueueManagerVersionOptions.SetQueueManagerID(parts[1]) + + hasChange := false + + if d.HasChange("version") { + oldVersion, newVersion := d.GetChange("version") + if IsVersionDowngrade(oldVersion.(string), newVersion.(string)) { + return diag.FromErr(fmt.Errorf("Version downgrade is not allowed")) + } + setQueueManagerVersionOptions.SetVersion(newVersion.(string)) + hasChange = true + } + + if hasChange { + _, response, err := mqcloudClient.SetQueueManagerVersionWithContext(context, setQueueManagerVersionOptions) + if err != nil { + log.Printf("[DEBUG] SetQueueManagerVersionWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("SetQueueManagerVersionWithContext failed %s\n%s", err, response)) + } + if waitForQmStatus { + _, err = waitForQmStatusUpdate(context, d, meta) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error waiting for Queue Manager (%s) to be in running state: %s", *setQueueManagerVersionOptions.QueueManagerID, err)) + } + } + } + + return resourceIbmMqcloudQueueManagerRead(context, d, meta) +} + +func resourceIbmMqcloudQueueManagerDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return diag.FromErr(err) + } + + err = checkSIPlan(d, meta) + if err != nil { + return diag.FromErr(fmt.Errorf("Delete Queue Manager failed %s", err)) + } + + deleteQueueManagerOptions := &mqcloudv1.DeleteQueueManagerOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteQueueManagerOptions.SetServiceInstanceGuid(parts[0]) + deleteQueueManagerOptions.SetQueueManagerID(parts[1]) + + _, response, err := mqcloudClient.DeleteQueueManagerWithContext(context, deleteQueueManagerOptions) + if err != nil { + log.Printf("[DEBUG] DeleteQueueManagerWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteQueueManagerWithContext failed %s\n%s", err, response)) + } + if waitForQmStatus { + _, err = waitForQueueManagerToDelete(context, d, meta) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error waiting for Queue Manager (%s) to be in running state: %s", *deleteQueueManagerOptions.QueueManagerID, err)) + } + } + d.SetId("") + + return nil +} diff --git a/ibm/service/mqcloud/resource_ibm_mqcloud_queue_manager_test.go b/ibm/service/mqcloud/resource_ibm_mqcloud_queue_manager_test.go new file mode 100644 index 0000000000..a6ccbd7feb --- /dev/null +++ b/ibm/service/mqcloud/resource_ibm_mqcloud_queue_manager_test.go @@ -0,0 +1,182 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package mqcloud_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/mqcloud-go-sdk/mqcloudv1" +) + +func TestAccIbmMqcloudQueueManagerBasic(t *testing.T) { + t.Parallel() + var conf mqcloudv1.QueueManagerDetails + serviceInstanceGuid := acc.MqcloudInstanceID + name := "queue_manager_basic" + location := "ibmcloud_eu_de" + size := "small" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmMqcloudQueueManagerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudQueueManagerConfigBasic(serviceInstanceGuid, name, location, size), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmMqcloudQueueManagerExists("ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", conf), + resource.TestCheckResourceAttr("ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "service_instance_guid", serviceInstanceGuid), + resource.TestCheckResourceAttr("ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "name", name), + resource.TestCheckResourceAttr("ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "location", location), + resource.TestCheckResourceAttr("ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "size", size), + ), + }, + }, + }) +} + +func TestAccIbmMqcloudQueueManagerAllArgs(t *testing.T) { + t.Parallel() + var conf mqcloudv1.QueueManagerDetails + serviceInstanceGuid := acc.MqcloudInstanceID + name := "queue_manager_allargs" + displayName := "queue_manager_allargs" + location := "ibmcloud_eu_de" + size := "small" + version := "9.3.3_3" + versionUpdate := "9.3.4_1" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmMqcloudQueueManagerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudQueueManagerConfig(serviceInstanceGuid, name, displayName, location, size, version), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmMqcloudQueueManagerExists("ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", conf), + resource.TestCheckResourceAttr("ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "service_instance_guid", serviceInstanceGuid), + resource.TestCheckResourceAttr("ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "name", name), + resource.TestCheckResourceAttr("ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "display_name", displayName), + resource.TestCheckResourceAttr("ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "location", location), + resource.TestCheckResourceAttr("ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "size", size), + resource.TestCheckResourceAttr("ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "version", version), + ), + }, + { + Config: testAccCheckIbmMqcloudQueueManagerConfig(serviceInstanceGuid, name, displayName, location, size, versionUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "service_instance_guid", serviceInstanceGuid), + resource.TestCheckResourceAttr("ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "name", name), + resource.TestCheckResourceAttr("ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "display_name", displayName), + resource.TestCheckResourceAttr("ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "location", location), + resource.TestCheckResourceAttr("ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "size", size), + resource.TestCheckResourceAttr("ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", "version", versionUpdate), + ), + }, + { + ResourceName: "ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIbmMqcloudQueueManagerConfigBasic(serviceInstanceGuid string, name string, location string, size string) string { + return fmt.Sprintf(` + resource "ibm_mqcloud_queue_manager" "mqcloud_queue_manager_instance" { + service_instance_guid = "%s" + name = "%s" + location = "%s" + size = "%s" + } + `, serviceInstanceGuid, name, location, size) +} + +func testAccCheckIbmMqcloudQueueManagerConfig(serviceInstanceGuid string, name string, displayName string, location string, size string, version string) string { + return fmt.Sprintf(` + + resource "ibm_mqcloud_queue_manager" "mqcloud_queue_manager_instance" { + service_instance_guid = "%s" + name = "%s" + display_name = "%s" + location = "%s" + size = "%s" + version = "%s" + } + `, serviceInstanceGuid, name, displayName, location, size, version) +} + +func testAccCheckIbmMqcloudQueueManagerExists(n string, obj mqcloudv1.QueueManagerDetails) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + mqcloudClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MqcloudV1() + if err != nil { + return err + } + + getQueueManagerOptions := &mqcloudv1.GetQueueManagerOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getQueueManagerOptions.SetServiceInstanceGuid(parts[0]) + getQueueManagerOptions.SetQueueManagerID(parts[1]) + + queueManagerDetails, _, err := mqcloudClient.GetQueueManager(getQueueManagerOptions) + if err != nil { + return err + } + + obj = *queueManagerDetails + return nil + } +} + +func testAccCheckIbmMqcloudQueueManagerDestroy(s *terraform.State) error { + mqcloudClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MqcloudV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_mqcloud_queue_manager" { + continue + } + + getQueueManagerOptions := &mqcloudv1.GetQueueManagerOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getQueueManagerOptions.SetServiceInstanceGuid(parts[0]) + getQueueManagerOptions.SetQueueManagerID(parts[1]) + + // Try to find the key + _, response, err := mqcloudClient.GetQueueManager(getQueueManagerOptions) + + if err == nil { + return fmt.Errorf("mqcloud_queue_manager_instance still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for mqcloud_queue_manager_instance (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/mqcloud/resource_ibm_mqcloud_truststore_certificate.go b/ibm/service/mqcloud/resource_ibm_mqcloud_truststore_certificate.go new file mode 100644 index 0000000000..63a35c247e --- /dev/null +++ b/ibm/service/mqcloud/resource_ibm_mqcloud_truststore_certificate.go @@ -0,0 +1,297 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package mqcloud + +import ( + "context" + "fmt" + "io" + "log" + "os" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/mqcloud-go-sdk/mqcloudv1" +) + +func ResourceIbmMqcloudTruststoreCertificate() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIbmMqcloudTruststoreCertificateCreate, + ReadContext: resourceIbmMqcloudTruststoreCertificateRead, + DeleteContext: resourceIbmMqcloudTruststoreCertificateDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "service_instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_mqcloud_truststore_certificate", "service_instance_guid"), + Description: "The GUID that uniquely identifies the MQ on Cloud service instance.", + }, + "queue_manager_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_mqcloud_truststore_certificate", "queue_manager_id"), + Description: "The id of the queue manager to retrieve its full details.", + }, + "label": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_mqcloud_truststore_certificate", "label"), + Description: "Certificate label in queue manager store.", + }, + "certificate_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of certificate.", + }, + "fingerprint_sha256": { + Type: schema.TypeString, + Computed: true, + Description: "Fingerprint SHA256.", + }, + "subject_dn": { + Type: schema.TypeString, + Computed: true, + Description: "Subject's Distinguished Name.", + }, + "subject_cn": { + Type: schema.TypeString, + Computed: true, + Description: "Subject's Common Name.", + }, + "issuer_dn": { + Type: schema.TypeString, + Computed: true, + Description: "Issuer's Distinguished Name.", + }, + "issuer_cn": { + Type: schema.TypeString, + Computed: true, + Description: "Issuer's Common Name.", + }, + "issued": { + Type: schema.TypeString, + Computed: true, + Description: "The Date the certificate was issued.", + }, + "expiry": { + Type: schema.TypeString, + Computed: true, + Description: "Expiry date for the certificate.", + }, + "trusted": { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether a certificate is trusted.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this trust store certificate.", + }, + "certificate_id": { + Type: schema.TypeString, + Computed: true, + Description: "Id of the certificate.", + }, + "certificate_file": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The filename and path of the certificate to be uploaded.", + }, + }, + } +} + +func ResourceIbmMqcloudTruststoreCertificateValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "service_instance_guid", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "queue_manager_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[0-9a-fA-F]{32}$`, + MinValueLength: 32, + MaxValueLength: 32, + }, + validate.ValidateSchema{ + Identifier: "label", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-zA-Z0-9_.]*$`, + MinValueLength: 1, + MaxValueLength: 64, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_mqcloud_truststore_certificate", Schema: validateSchema} + return &resourceValidator +} + +func resourceIbmMqcloudTruststoreCertificateCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return diag.FromErr(err) + } + err = checkSIPlan(d, meta) + if err != nil { + return diag.FromErr(fmt.Errorf("Create Truststore Certificate failed %s", err)) + } + + createTrustStorePemCertificateOptions := &mqcloudv1.CreateTrustStorePemCertificateOptions{} + + createTrustStorePemCertificateOptions.SetServiceInstanceGuid(d.Get("service_instance_guid").(string)) + createTrustStorePemCertificateOptions.SetQueueManagerID(d.Get("queue_manager_id").(string)) + createTrustStorePemCertificateOptions.SetLabel(d.Get("label").(string)) + //Custom code to read certs and pass to SDK + certBytes, err := os.ReadFile(d.Get("certificate_file").(string)) // just pass the file name + if err != nil { + fmt.Print(err) + } + certString := string(certBytes) // convert content to a 'string' + rc := io.NopCloser(strings.NewReader(certString)) + // certificateFileModel, err := resourceIbmMqcloudTruststoreCertificateMapToio.ReadCloser(d.Get("certificate_file.0").(map[string]interface{})) + // if err != nil { + // return diag.FromErr(err) + // } + createTrustStorePemCertificateOptions.SetCertificateFile(rc) + + trustStoreCertificateDetails, response, err := mqcloudClient.CreateTrustStorePemCertificateWithContext(context, createTrustStorePemCertificateOptions) + if err != nil { + log.Printf("[DEBUG] CreateTrustStorePemCertificateWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateTrustStorePemCertificateWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s/%s", *createTrustStorePemCertificateOptions.ServiceInstanceGuid, *createTrustStorePemCertificateOptions.QueueManagerID, *trustStoreCertificateDetails.ID)) + + return resourceIbmMqcloudTruststoreCertificateRead(context, d, meta) +} + +func resourceIbmMqcloudTruststoreCertificateRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return diag.FromErr(err) + } + + getTrustStoreCertificateOptions := &mqcloudv1.GetTrustStoreCertificateOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getTrustStoreCertificateOptions.SetServiceInstanceGuid(parts[0]) + getTrustStoreCertificateOptions.SetQueueManagerID(parts[1]) + getTrustStoreCertificateOptions.SetCertificateID(parts[2]) + + trustStoreCertificateDetails, response, err := mqcloudClient.GetTrustStoreCertificateWithContext(context, getTrustStoreCertificateOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetTrustStoreCertificateWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetTrustStoreCertificateWithContext failed %s\n%s", err, response)) + } + if err = d.Set("service_instance_guid", parts[0]); err != nil { + return diag.FromErr(fmt.Errorf("Error setting service_instance_guid: %s", err)) + } + if err = d.Set("queue_manager_id", parts[1]); err != nil { + return diag.FromErr(fmt.Errorf("Error setting queue_manager_id: %s", err)) + } + downloadCertificatePath := "./certificates/truststore/" + *trustStoreCertificateDetails.Label + ".pem" + if err = d.Set("certificate_file", downloadCertificatePath); err != nil { + return diag.FromErr(fmt.Errorf("Error setting certificate_file: %s", err)) + } + if err = d.Set("label", trustStoreCertificateDetails.Label); err != nil { + return diag.FromErr(fmt.Errorf("Error setting label: %s", err)) + } + if err = d.Set("certificate_type", trustStoreCertificateDetails.CertificateType); err != nil { + return diag.FromErr(fmt.Errorf("Error setting certificate_type: %s", err)) + } + if err = d.Set("fingerprint_sha256", trustStoreCertificateDetails.FingerprintSha256); err != nil { + return diag.FromErr(fmt.Errorf("Error setting fingerprint_sha256: %s", err)) + } + if err = d.Set("subject_dn", trustStoreCertificateDetails.SubjectDn); err != nil { + return diag.FromErr(fmt.Errorf("Error setting subject_dn: %s", err)) + } + if err = d.Set("subject_cn", trustStoreCertificateDetails.SubjectCn); err != nil { + return diag.FromErr(fmt.Errorf("Error setting subject_cn: %s", err)) + } + if err = d.Set("issuer_dn", trustStoreCertificateDetails.IssuerDn); err != nil { + return diag.FromErr(fmt.Errorf("Error setting issuer_dn: %s", err)) + } + if err = d.Set("issuer_cn", trustStoreCertificateDetails.IssuerCn); err != nil { + return diag.FromErr(fmt.Errorf("Error setting issuer_cn: %s", err)) + } + if err = d.Set("issued", flex.DateTimeToString(trustStoreCertificateDetails.Issued)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting issued: %s", err)) + } + if err = d.Set("expiry", flex.DateTimeToString(trustStoreCertificateDetails.Expiry)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting expiry: %s", err)) + } + if err = d.Set("trusted", trustStoreCertificateDetails.Trusted); err != nil { + return diag.FromErr(fmt.Errorf("Error setting trusted: %s", err)) + } + if err = d.Set("href", trustStoreCertificateDetails.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + if err = d.Set("certificate_id", trustStoreCertificateDetails.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting certificate_id: %s", err)) + } + + return nil +} + +func resourceIbmMqcloudTruststoreCertificateDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return diag.FromErr(err) + } + err = checkSIPlan(d, meta) + if err != nil { + return diag.FromErr(fmt.Errorf("Delete Truststore Certificate failed %s", err)) + } + deleteTrustStoreCertificateOptions := &mqcloudv1.DeleteTrustStoreCertificateOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteTrustStoreCertificateOptions.SetServiceInstanceGuid(parts[0]) + deleteTrustStoreCertificateOptions.SetQueueManagerID(parts[1]) + deleteTrustStoreCertificateOptions.SetCertificateID(parts[2]) + + response, err := mqcloudClient.DeleteTrustStoreCertificateWithContext(context, deleteTrustStoreCertificateOptions) + if err != nil { + log.Printf("[DEBUG] DeleteTrustStoreCertificateWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteTrustStoreCertificateWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/mqcloud/resource_ibm_mqcloud_truststore_certificate_test.go b/ibm/service/mqcloud/resource_ibm_mqcloud_truststore_certificate_test.go new file mode 100644 index 0000000000..80acc0e4a1 --- /dev/null +++ b/ibm/service/mqcloud/resource_ibm_mqcloud_truststore_certificate_test.go @@ -0,0 +1,163 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package mqcloud_test + +import ( + "fmt" + "testing" + + "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" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/mqcloud-go-sdk/mqcloudv1" +) + +func TestAccIbmMqcloudTruststoreCertificateBasic(t *testing.T) { + var conf mqcloudv1.TrustStoreCertificateDetails + serviceInstanceGuid := acc.MqcloudInstanceID + queueManagerID := acc.MqcloudQueueManagerID + label := fmt.Sprintf("tf_label_%d", acctest.RandIntRange(10, 100)) + certificateFile := acc.MqcloudTSCertFilePath + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmMqcloudTruststoreCertificateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudTruststoreCertificateConfigBasic(serviceInstanceGuid, queueManagerID, label, certificateFile), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmMqcloudTruststoreCertificateExists("ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", conf), + resource.TestCheckResourceAttr("ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "service_instance_guid", serviceInstanceGuid), + resource.TestCheckResourceAttr("ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "queue_manager_id", queueManagerID), + resource.TestCheckResourceAttr("ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "label", label), + ), + }, + }, + }) +} + +func TestAccIbmMqcloudTruststoreCertificateAllArgs(t *testing.T) { + var conf mqcloudv1.TrustStoreCertificateDetails + serviceInstanceGuid := acc.MqcloudInstanceID + queueManagerID := acc.MqcloudQueueManagerID + label := fmt.Sprintf("tf_label_%d", acctest.RandIntRange(10, 100)) + certificateFile := acc.MqcloudTSCertFilePath + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmMqcloudTruststoreCertificateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudTruststoreCertificateConfig(serviceInstanceGuid, queueManagerID, label, certificateFile), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmMqcloudTruststoreCertificateExists("ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", conf), + resource.TestCheckResourceAttr("ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "service_instance_guid", serviceInstanceGuid), + resource.TestCheckResourceAttr("ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "queue_manager_id", queueManagerID), + resource.TestCheckResourceAttr("ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", "label", label), + ), + }, + { + ResourceName: "ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIbmMqcloudTruststoreCertificateConfigBasic(serviceInstanceGuid string, queueManagerID string, label string, certificateFile string) string { + return fmt.Sprintf(` + resource "ibm_mqcloud_truststore_certificate" "mqcloud_truststore_certificate_instance" { + service_instance_guid = "%s" + queue_manager_id = "%s" + label = "%s" + certificate_file = "%s" + } + `, serviceInstanceGuid, queueManagerID, label, certificateFile) +} + +func testAccCheckIbmMqcloudTruststoreCertificateConfig(serviceInstanceGuid string, queueManagerID string, label string, certificateFile string) string { + return fmt.Sprintf(` + + resource "ibm_mqcloud_truststore_certificate" "mqcloud_truststore_certificate_instance" { + service_instance_guid = "%s" + queue_manager_id = "%s" + label = "%s" + certificate_file = "%s" + } + `, serviceInstanceGuid, queueManagerID, label, certificateFile) +} + +func testAccCheckIbmMqcloudTruststoreCertificateExists(n string, obj mqcloudv1.TrustStoreCertificateDetails) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + mqcloudClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MqcloudV1() + if err != nil { + return err + } + + getTrustStoreCertificateOptions := &mqcloudv1.GetTrustStoreCertificateOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getTrustStoreCertificateOptions.SetServiceInstanceGuid(parts[0]) + getTrustStoreCertificateOptions.SetQueueManagerID(parts[1]) + getTrustStoreCertificateOptions.SetCertificateID(parts[2]) + + trustStoreCertificateDetails, _, err := mqcloudClient.GetTrustStoreCertificate(getTrustStoreCertificateOptions) + if err != nil { + return err + } + + obj = *trustStoreCertificateDetails + return nil + } +} + +func testAccCheckIbmMqcloudTruststoreCertificateDestroy(s *terraform.State) error { + mqcloudClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MqcloudV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_mqcloud_truststore_certificate" { + continue + } + + getTrustStoreCertificateOptions := &mqcloudv1.GetTrustStoreCertificateOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getTrustStoreCertificateOptions.SetServiceInstanceGuid(parts[0]) + getTrustStoreCertificateOptions.SetQueueManagerID(parts[1]) + getTrustStoreCertificateOptions.SetCertificateID(parts[2]) + + // Try to find the key + _, response, err := mqcloudClient.GetTrustStoreCertificate(getTrustStoreCertificateOptions) + + if err == nil { + return fmt.Errorf("mqcloud_truststore_certificate still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for mqcloud_truststore_certificate (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/mqcloud/resource_ibm_mqcloud_user.go b/ibm/service/mqcloud/resource_ibm_mqcloud_user.go new file mode 100644 index 0000000000..3509b1d1da --- /dev/null +++ b/ibm/service/mqcloud/resource_ibm_mqcloud_user.go @@ -0,0 +1,196 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package mqcloud + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/mqcloud-go-sdk/mqcloudv1" +) + +func ResourceIbmMqcloudUser() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIbmMqcloudUserCreate, + ReadContext: resourceIbmMqcloudUserRead, + DeleteContext: resourceIbmMqcloudUserDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "service_instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_mqcloud_user", "service_instance_guid"), + Description: "The GUID that uniquely identifies the MQ on Cloud service instance.", + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_mqcloud_user", "name"), + Description: "The shortname of the user that will be used as the IBM MQ administrator in interactions with a queue manager for this service instance.", + }, + "email": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_mqcloud_user", "email"), + Description: "The email of the user.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for the user details.", + }, + "user_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the user which was allocated on creation, and can be used for delete calls.", + }, + }, + } +} + +func ResourceIbmMqcloudUserValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "service_instance_guid", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-z][-a-z0-9]*$`, + MinValueLength: 1, + MaxValueLength: 12, + }, + validate.ValidateSchema{ + Identifier: "email", + ValidateFunctionIdentifier: validate.StringLenBetween, + Type: validate.TypeString, + Required: true, + MinValueLength: 5, + MaxValueLength: 253, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_mqcloud_user", Schema: validateSchema} + return &resourceValidator +} + +func resourceIbmMqcloudUserCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return diag.FromErr(err) + } + err = checkSIPlan(d, meta) + if err != nil { + return diag.FromErr(fmt.Errorf("Create User failed %s", err)) + } + createUserOptions := &mqcloudv1.CreateUserOptions{} + + createUserOptions.SetServiceInstanceGuid(d.Get("service_instance_guid").(string)) + createUserOptions.SetEmail(d.Get("email").(string)) + createUserOptions.SetName(d.Get("name").(string)) + + userDetails, response, err := mqcloudClient.CreateUserWithContext(context, createUserOptions) + if err != nil { + log.Printf("[DEBUG] CreateUserWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateUserWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s/%s", *createUserOptions.ServiceInstanceGuid, *userDetails.ID)) + + return resourceIbmMqcloudUserRead(context, d, meta) +} + +func resourceIbmMqcloudUserRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return diag.FromErr(err) + } + + getUserOptions := &mqcloudv1.GetUserOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + getUserOptions.SetServiceInstanceGuid(parts[0]) + getUserOptions.SetUserID(parts[1]) + + userDetails, response, err := mqcloudClient.GetUserWithContext(context, getUserOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetUserWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetUserWithContext failed %s\n%s", err, response)) + } + if err = d.Set("service_instance_guid", parts[0]); err != nil { + return diag.FromErr(fmt.Errorf("Error setting service_instance_guid: %s", err)) + } + if err = d.Set("name", userDetails.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("email", userDetails.Email); err != nil { + return diag.FromErr(fmt.Errorf("Error setting email: %s", err)) + } + if err = d.Set("href", userDetails.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + if err = d.Set("user_id", userDetails.ID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting user_id: %s", err)) + } + + return nil +} + +func resourceIbmMqcloudUserDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return diag.FromErr(err) + } + err = checkSIPlan(d, meta) + if err != nil { + return diag.FromErr(fmt.Errorf("Delete User failed %s", err)) + } + deleteUserOptions := &mqcloudv1.DeleteUserOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return diag.FromErr(err) + } + + deleteUserOptions.SetServiceInstanceGuid(parts[0]) + deleteUserOptions.SetUserID(parts[1]) + + response, err := mqcloudClient.DeleteUserWithContext(context, deleteUserOptions) + if err != nil { + log.Printf("[DEBUG] DeleteUserWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteUserWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/mqcloud/resource_ibm_mqcloud_user_test.go b/ibm/service/mqcloud/resource_ibm_mqcloud_user_test.go new file mode 100644 index 0000000000..551827f583 --- /dev/null +++ b/ibm/service/mqcloud/resource_ibm_mqcloud_user_test.go @@ -0,0 +1,157 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package mqcloud_test + +import ( + "fmt" + "testing" + + "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" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/mqcloud-go-sdk/mqcloudv1" +) + +func TestAccIbmMqcloudUserBasic(t *testing.T) { + var conf mqcloudv1.UserDetails + serviceInstanceGuid := acc.MqcloudInstanceID + name := fmt.Sprintf("tfname%d", acctest.RandIntRange(10, 100)) + email := fmt.Sprintf("tfemail%d@ibm.com", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmMqcloudUserDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudUserConfigBasic(serviceInstanceGuid, name, email), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmMqcloudUserExists("ibm_mqcloud_user.mqcloud_user_instance", conf), + resource.TestCheckResourceAttr("ibm_mqcloud_user.mqcloud_user_instance", "service_instance_guid", serviceInstanceGuid), + resource.TestCheckResourceAttr("ibm_mqcloud_user.mqcloud_user_instance", "name", name), + resource.TestCheckResourceAttr("ibm_mqcloud_user.mqcloud_user_instance", "email", email), + ), + }, + }, + }) +} + +func TestAccIbmMqcloudUserAllArgs(t *testing.T) { + var conf mqcloudv1.UserDetails + serviceInstanceGuid := acc.MqcloudInstanceID + name := fmt.Sprintf("tfname%d", acctest.RandIntRange(10, 100)) + email := fmt.Sprintf("tfemail%d@ibm.com", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmMqcloudUserDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudUserConfig(serviceInstanceGuid, name, email), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmMqcloudUserExists("ibm_mqcloud_user.mqcloud_user_instance", conf), + resource.TestCheckResourceAttr("ibm_mqcloud_user.mqcloud_user_instance", "service_instance_guid", serviceInstanceGuid), + resource.TestCheckResourceAttr("ibm_mqcloud_user.mqcloud_user_instance", "name", name), + resource.TestCheckResourceAttr("ibm_mqcloud_user.mqcloud_user_instance", "email", email), + ), + }, + { + ResourceName: "ibm_mqcloud_user.mqcloud_user_instance", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIbmMqcloudUserConfigBasic(serviceInstanceGuid string, name string, email string) string { + return fmt.Sprintf(` + resource "ibm_mqcloud_user" "mqcloud_user_instance" { + service_instance_guid = "%s" + name = "%s" + email = "%s" + } + `, serviceInstanceGuid, name, email) +} + +func testAccCheckIbmMqcloudUserConfig(serviceInstanceGuid string, name string, email string) string { + return fmt.Sprintf(` + + resource "ibm_mqcloud_user" "mqcloud_user_instance" { + service_instance_guid = "%s" + name = "%s" + email = "%s" + } + `, serviceInstanceGuid, name, email) +} + +func testAccCheckIbmMqcloudUserExists(n string, obj mqcloudv1.UserDetails) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + mqcloudClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MqcloudV1() + if err != nil { + return err + } + + getUserOptions := &mqcloudv1.GetUserOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getUserOptions.SetServiceInstanceGuid(parts[0]) + getUserOptions.SetUserID(parts[1]) + + userDetails, _, err := mqcloudClient.GetUser(getUserOptions) + if err != nil { + return err + } + + obj = *userDetails + return nil + } +} + +func testAccCheckIbmMqcloudUserDestroy(s *terraform.State) error { + mqcloudClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).MqcloudV1() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_mqcloud_user" { + continue + } + + getUserOptions := &mqcloudv1.GetUserOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getUserOptions.SetServiceInstanceGuid(parts[0]) + getUserOptions.SetUserID(parts[1]) + + // Try to find the key + _, response, err := mqcloudClient.GetUser(getUserOptions) + + if err == nil { + return fmt.Errorf("mqcloud_user still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for mqcloud_user (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/mqcloud/utils.go b/ibm/service/mqcloud/utils.go new file mode 100644 index 0000000000..877b5ed79b --- /dev/null +++ b/ibm/service/mqcloud/utils.go @@ -0,0 +1,196 @@ +package mqcloud + +import ( + "context" + "fmt" + "os" + "strings" + "time" + + "strconv" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/IBM/mqcloud-go-sdk/mqcloudv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func loadWaitForQmStatusEnvVar() bool { + envValue := os.Getenv("IBMCLOUD_MQCLOUD_WAIT_FOR_QM_STATUS") + return strings.ToLower(envValue) != "false" +} + +var waitForQmStatus = loadWaitForQmStatusEnvVar() +var planCache = make(map[string]string) + +const qmStatus = "running" +const qmCreating = "initializing" +const isQueueManagerDeleting = "true" +const isQueueManagerDeleteDone = "true" +const reservedDeploymentPlan = "reserved-deployment" +const enforceReservedDeploymentPlan = true + +// waitForQmStatusUpdate Waits for QM to be in running state +func waitForQmStatusUpdate(context context.Context, d *schema.ResourceData, meta interface{}) (interface{}, error) { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return "", err + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{qmCreating}, + Target: []string{qmStatus}, + Refresh: func() (interface{}, string, error) { + getQueueManagerStatusOptions := &mqcloudv1.GetQueueManagerStatusOptions{} + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return nil, "", err + } + getQueueManagerStatusOptions.SetServiceInstanceGuid(parts[0]) + getQueueManagerStatusOptions.SetQueueManagerID(parts[1]) + queueManagerStatus, response, err := mqcloudClient.GetQueueManagerStatusWithContext(context, getQueueManagerStatusOptions) + if err != nil { + return "", "", fmt.Errorf("GetQueueManagerWithContext ...... %s err: %s", response, err) + } + if queueManagerStatus == nil || queueManagerStatus.Status == nil { + return nil, "", fmt.Errorf("queueManagerStatus or queueManagerStatus.Status is nil") + } + fmt.Println("The queue manager is currently in the " + *queueManagerStatus.Status + " state ....") + + if *queueManagerStatus.Status == "running" { + return queueManagerStatus, qmStatus, nil + } else if *queueManagerStatus.Status == "initialization_failed" || *queueManagerStatus.Status == "restore_failed" || *queueManagerStatus.Status == "status_not_available" { + return queueManagerStatus, qmStatus, fmt.Errorf("%s", err) + } + return queueManagerStatus, qmCreating, nil + }, + Timeout: d.Timeout(schema.TimeoutCreate), + Delay: 10 * time.Second, + MinTimeout: 30 * time.Second, + } + return stateConf.WaitForStateContext(context) +} + +func waitForQueueManagerToDelete(context context.Context, d *schema.ResourceData, meta interface{}) (interface{}, error) { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + return false, err + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{isQueueManagerDeleting}, + Target: []string{isQueueManagerDeleteDone}, + Refresh: func() (interface{}, string, error) { + getQueueManagerOptions := &mqcloudv1.GetQueueManagerOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return "", "", err + } + + getQueueManagerOptions.SetServiceInstanceGuid(parts[0]) + getQueueManagerOptions.SetQueueManagerID(parts[1]) + + queueManagerDetails, response, err := mqcloudClient.GetQueueManagerWithContext(context, getQueueManagerOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return queueManagerDetails, isQueueManagerDeleteDone, nil + } + return nil, "", err + } + return queueManagerDetails, isQueueManagerDeleting, nil + }, + Timeout: d.Timeout(schema.TimeoutDelete), + Delay: 60 * time.Second, + MinTimeout: 60 * time.Second, + } + + return stateConf.WaitForStateContext(context) +} + +// checkSIPlan checks whether a Service Instance (SI) is in a Reserved Deployment. +func checkSIPlan(d *schema.ResourceData, meta interface{}) error { + if !enforceReservedDeploymentPlan { + return nil + } + + instanceID := d.Get("service_instance_guid").(string) + // Check cache first + if plan, found := planCache[instanceID]; found { + return handlePlanCheck(plan, instanceID) + } + + // Creating a Resource Controller Client + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return fmt.Errorf("[ERROR] Failed to create Resource Controller Client: %s", err) + } + + // Getting the resource instance + rsInst := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + instance, response, err := rsConClient.GetResourceInstance(&rsInst) + if err != nil { + return fmt.Errorf("[ERROR] Failed to retrieve resource instance: %s, Response: %s", err, response) + } + + // Creating a Resource Catalog Client + rsCatClient, err := meta.(conns.ClientSession).ResourceCatalogAPI() + if err != nil { + return fmt.Errorf("[ERROR] Failed to create Resource Catalog Client: %s", err) + } + rsCatRepo := rsCatClient.ResourceCatalog() + + // Checking the service plan + plan, err := rsCatRepo.GetServicePlanName(*instance.ResourcePlanID) + if err != nil { + return fmt.Errorf("[ERROR] Failed to retrieve service plan: %s", err) + } + + // Update cache + planCache[instanceID] = plan + + return handlePlanCheck(plan, instanceID) +} + +func handlePlanCheck(plan string, instanceID string) error { + if plan != reservedDeploymentPlan { + return fmt.Errorf("[ERROR] Terraform is only supported for Reserved Deployment Plan. Your Service Plan is: %s for the instance %s", plan, instanceID) + } + return nil +} + +func IsVersionDowngrade(oldVersion, newVersion string) bool { + oldParts := strings.Split(oldVersion, ".") + newParts := strings.Split(newVersion, ".") + + for i := 0; i < len(oldParts); i++ { + oldPartNum := strings.Split(oldParts[i], "_")[0] + newPartNum := strings.Split(newParts[i], "_")[0] + + oldPart, _ := strconv.Atoi(oldPartNum) + newPart, _ := strconv.Atoi(newPartNum) + + if newPart < oldPart { + return true + } else if newPart > oldPart { + return false + } + } + + oldPatchNum := strings.Split(oldParts[len(oldParts)-1], "_") + newPatchNum := strings.Split(newParts[len(newParts)-1], "_") + + if len(oldPatchNum) > 1 && len(newPatchNum) > 1 { + oldPatch, _ := strconv.Atoi(oldPatchNum[1]) + newPatch, _ := strconv.Atoi(newPatchNum[1]) + + return newPatch < oldPatch + } + + return false +} diff --git a/website/allowed-subcategories.txt b/website/allowed-subcategories.txt index 1e97423139..f80f98af65 100644 --- a/website/allowed-subcategories.txt +++ b/website/allowed-subcategories.txt @@ -26,6 +26,7 @@ Internet services Key Management Service Kubernetes Service Metrics Router +MQ on Cloud Object Storage Power Systems Project diff --git a/website/docs/d/mqcloud_application.html.markdown b/website/docs/d/mqcloud_application.html.markdown new file mode 100644 index 0000000000..0e854d5c8a --- /dev/null +++ b/website/docs/d/mqcloud_application.html.markdown @@ -0,0 +1,44 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_mqcloud_application" +description: |- + Get information about mqcloud_application +subcategory: "MQ on Cloud" +--- + +# ibm_mqcloud_application + +Provides a read-only data source to retrieve information about a mqcloud_application. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_mqcloud_application" "mqcloud_application" { + name = ibm_mqcloud_application.mqcloud_application_instance.name + service_instance_guid = ibm_mqcloud_application.mqcloud_application_instance.service_instance_guid +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +* `name` - (Optional, String) The name of the application - conforming to MQ rules. + * Constraints: The maximum length is `12` characters. The minimum length is `1` character. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQ on Cloud service instance. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/`. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +* `id` - The unique identifier of the mqcloud_application. +* `applications` - (List) List of applications. + * Constraints: The maximum length is `50` items. The minimum length is `0` items. +Nested schema for **applications**: + * `create_api_key_uri` - (String) The URI to create a new apikey for the application. + * `href` - (String) The URL for this application. + * `id` - (String) The ID of the application which was allocated on creation, and can be used for delete calls. + * `name` - (String) The name of the application - conforming to MQ rules. + * Constraints: The maximum length is `12` characters. The minimum length is `1` character. + diff --git a/website/docs/d/mqcloud_keystore_certificate.html.markdown b/website/docs/d/mqcloud_keystore_certificate.html.markdown new file mode 100644 index 0000000000..6222ecd784 --- /dev/null +++ b/website/docs/d/mqcloud_keystore_certificate.html.markdown @@ -0,0 +1,63 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_mqcloud_keystore_certificate" +description: |- + Get information about mqcloud_keystore_certificate +subcategory: "MQ on Cloud" +--- + +# ibm_mqcloud_keystore_certificate + +Provides a read-only data source to retrieve information about a mqcloud_keystore_certificate. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_mqcloud_keystore_certificate" "mqcloud_keystore_certificate" { + label = ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance.label + queue_manager_id = ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance.queue_manager_id + service_instance_guid = ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate_instance.service_instance_guid +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +* `label` - (Optional, String) Certificate label in queue manager store. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9_.]*$/`. +* `queue_manager_id` - (Required, Forces new resource, String) The id of the queue manager to retrieve its full details. + * Constraints: The maximum length is `32` characters. The minimum length is `32` characters. The value must match regular expression `/^[0-9a-fA-F]{32}$/`. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQ on Cloud service instance. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/`. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +* `id` - The unique identifier of the mqcloud_keystore_certificate. +* `key_store` - (List) The list of key store certificates. + * Constraints: The maximum length is `50` items. The minimum length is `0` items. +Nested schema for **key_store**: + * `certificate_type` - (String) The type of certificate. + * Constraints: Allowable values are: `key_store`. + * `dns_names` - (List) The list of DNS names. + * Constraints: The maximum length is `200` items. The minimum length is `0` items. + * `dns_names_total_count` - (Integer) The total count of dns names. + * `expiry` - (String) Expiry date for the certificate. + * `fingerprint_sha256` - (String) Fingerprint SHA256. + * Constraints: The value must match regular expression `/^[A-F0-9]{2}(:[A-F0-9]{2}){31}$/`. + * `href` - (String) The URL for this key store certificate. + * `id` - (String) ID of the certificate. + * Constraints: The maximum length is `16` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9a-fA-F]*$/`. + * `is_default` - (Boolean) Indicates whether it is the queue manager's default certificate. + * `issued` - (String) Date certificate was issued. + * `issuer_cn` - (String) Issuer's Common Name. + * `issuer_dn` - (String) Issuer's Distinguished Name. + * `label` - (String) Certificate label in queue manager store. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9_.]*$/`. + * `subject_cn` - (String) Subject's Common Name. + * `subject_dn` - (String) Subject's Distinguished Name. + +* `total_count` - (Integer) The total count of key store certificates. + diff --git a/website/docs/d/mqcloud_queue_manager.html.markdown b/website/docs/d/mqcloud_queue_manager.html.markdown new file mode 100644 index 0000000000..59bfc7c76b --- /dev/null +++ b/website/docs/d/mqcloud_queue_manager.html.markdown @@ -0,0 +1,60 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_mqcloud_queue_manager" +description: |- + Get information about mqcloud_queue_manager +subcategory: "MQ on Cloud" +--- + +# ibm_mqcloud_queue_manager + +Provides a read-only data source to retrieve information about a mqcloud_queue_manager. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_mqcloud_queue_manager" "mqcloud_queue_manager" { + name = ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance.name + service_instance_guid = ibm_mqcloud_queue_manager.mqcloud_queue_manager_instance.service_instance_guid +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +* `name` - (Optional, String) A queue manager name conforming to MQ restrictions. + * Constraints: The maximum length is `48` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9._]*$/`. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQ on Cloud service instance. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/`. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +* `id` - The unique identifier of the mqcloud_queue_manager. + +* `queue_managers` - (List) List of queue managers. + * Constraints: The maximum length is `50` items. The minimum length is `0` items. +Nested schema for **queue_managers**: + * `administrator_api_endpoint_url` - (String) The url through which to access the Admin REST APIs for this queue manager. + * `available_upgrade_versions_uri` - (String) The uri through which the available versions to upgrade to can be found for this queue manager. + * `connection_info_uri` - (String) The uri through which the CDDT for this queue manager can be obtained. + * `date_created` - (String) RFC3339 formatted UTC date for when the queue manager was created. + * `display_name` - (String) A displayable name for the queue manager - limited only in length. + * Constraints: The maximum length is `150` characters. + * `href` - (String) The URL for this queue manager. + * `id` - (String) The ID of the queue manager which was allocated on creation, and can be used for delete calls. + * `location` - (String) The locations in which the queue manager could be deployed. + * Constraints: The maximum length is `150` characters. The minimum length is `2` characters. The value must match regular expression `/^([^[:ascii:]]|[a-zA-Z0-9-._: ])+$/`. + * `name` - (String) A queue manager name conforming to MQ restrictions. + * Constraints: The maximum length is `48` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9._]*$/`. + * `rest_api_endpoint_url` - (String) The url through which to access REST APIs for this queue manager. + * `size` - (String) The queue manager sizes of deployment available. Deployment of lite queue managers for aws_us_east_1 and aws_eu_west_1 locations is not available. + * Constraints: Allowable values are: `lite`, `xsmall`, `small`, `medium`, `large`. + * `status_uri` - (String) A reference uri to get deployment status of the queue manager. + * `upgrade_available` - (Boolean) Describes whether an upgrade is available for this queue manager. + * `version` - (String) The MQ version of the queue manager. + * Constraints: The maximum length is `15` characters. The minimum length is `7` characters. The value must match regular expression `/^[0-9]+.[0-9]+.[0-9]+_[0-9]+$/`. + * `web_console_url` - (String) The url through which to access the web console for this queue manager. + diff --git a/website/docs/d/mqcloud_queue_manager_status.html.markdown b/website/docs/d/mqcloud_queue_manager_status.html.markdown new file mode 100644 index 0000000000..342ac508c9 --- /dev/null +++ b/website/docs/d/mqcloud_queue_manager_status.html.markdown @@ -0,0 +1,38 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_mqcloud_queue_manager_status" +description: |- + Get information about mqcloud_queue_manager_status +subcategory: "MQ on Cloud" +--- + +# ibm_mqcloud_queue_manager_status + +Provides a read-only data source to retrieve information about mqcloud_queue_manager_status. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_mqcloud_queue_manager_status" "mqcloud_queue_manager_status" { + queue_manager_id = var.queue_manager_id + service_instance_guid = var.service_instance_guid +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +* `queue_manager_id` - (Required, Forces new resource, String) The id of the queue manager to retrieve its full details. + * Constraints: The maximum length is `32` characters. The minimum length is `32` characters. The value must match regular expression `/^[0-9a-fA-F]{32}$/`. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQ on Cloud service instance. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/`. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +* `id` - The unique identifier of the mqcloud_queue_manager_status. +* `status` - (String) The deploying and failed states are not queue manager states, they are states which can occur when the request to deploy has been fired, or with that request has failed without producing a queue manager to have any state. The other states map to the queue manager states. State "ending" is either quiesing or ending immediately. State "ended" is either ended normally or endedimmediately. The others map one to one with queue manager states. + * Constraints: Allowable values are: `initializing`, `deploying`, `starting`, `running`, `stopping`, `stopped`, `status_not_available`, `deleting`, `failed`, `upgrading_version`, `updating_revision`, `initialization_failed`, `restoring_queue_manager`, `restoring_config`, `restore_failed`, `suspended`, `resumable`. + diff --git a/website/docs/d/mqcloud_truststore_certificate.html.markdown b/website/docs/d/mqcloud_truststore_certificate.html.markdown new file mode 100644 index 0000000000..5fb07ffb1a --- /dev/null +++ b/website/docs/d/mqcloud_truststore_certificate.html.markdown @@ -0,0 +1,60 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_mqcloud_truststore_certificate" +description: |- + Get information about mqcloud_truststore_certificate +subcategory: "MQ on Cloud" +--- + +# ibm_mqcloud_truststore_certificate + +Provides a read-only data source to retrieve information about a mqcloud_truststore_certificate. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_mqcloud_truststore_certificate" "mqcloud_truststore_certificate" { + label = ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance.label + queue_manager_id = ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance.queue_manager_id + service_instance_guid = ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance.service_instance_guid +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +* `label` - (Optional, String) Certificate label in queue manager store. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9_.]*$/`. +* `queue_manager_id` - (Required, Forces new resource, String) The id of the queue manager to retrieve its full details. + * Constraints: The maximum length is `32` characters. The minimum length is `32` characters. The value must match regular expression `/^[0-9a-fA-F]{32}$/`. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQ on Cloud service instance. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/`. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +* `id` - The unique identifier of the mqcloud_truststore_certificate. +* `total_count` - (Integer) The total count of trust store certificates. + +* `trust_store` - (List) The list of trust store certificates. + * Constraints: The maximum length is `50` items. The minimum length is `0` items. +Nested schema for **trust_store**: + * `certificate_type` - (String) The type of certificate. + * Constraints: Allowable values are: `trust_store`. + * `expiry` - (String) Expiry date for the certificate. + * `fingerprint_sha256` - (String) Fingerprint SHA256. + * Constraints: The value must match regular expression `/^[A-F0-9]{2}(:[A-F0-9]{2}){31}$/`. + * `href` - (String) The URL for this trust store certificate. + * `id` - (String) Id of the certificate. + * Constraints: The maximum length is `16` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9a-fA-F]*$/`. + * `issued` - (String) The Date the certificate was issued. + * `issuer_cn` - (String) Issuer's Common Name. + * `issuer_dn` - (String) Issuer's Distinguished Name. + * `label` - (String) Certificate label in queue manager store. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9_.]*$/`. + * `subject_cn` - (String) Subject's Common Name. + * `subject_dn` - (String) Subject's Distinguished Name. + * `trusted` - (Boolean) Indicates whether a certificate is trusted. + diff --git a/website/docs/d/mqcloud_user.html.markdown b/website/docs/d/mqcloud_user.html.markdown new file mode 100644 index 0000000000..89c1aa4db7 --- /dev/null +++ b/website/docs/d/mqcloud_user.html.markdown @@ -0,0 +1,46 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_mqcloud_user" +description: |- + Get information about mqcloud_user +subcategory: "MQ on Cloud" +--- + +# ibm_mqcloud_user + +Provides a read-only data source to retrieve information about a mqcloud_user. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_mqcloud_user" "mqcloud_user" { + name = ibm_mqcloud_user.mqcloud_user_instance.name + service_instance_guid = ibm_mqcloud_user.mqcloud_user_instance.service_instance_guid +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +* `name` - (Optional, String) The shortname of the user that will be used as the IBM MQ administrator in interactions with a queue manager for this service instance. + * Constraints: The maximum length is `12` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z][-a-z0-9]*$/`. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQ on Cloud service instance. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/`. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +* `id` - The unique identifier of the mqcloud_user. + +* `users` - (List) List of users. + * Constraints: The maximum length is `50` items. The minimum length is `0` items. +Nested schema for **users**: + * `email` - (String) The email of the user. + * Constraints: The maximum length is `253` characters. The minimum length is `5` characters. + * `href` - (String) The URL for the user details. + * `id` - (String) The ID of the user which was allocated on creation, and can be used for delete calls. + * `name` - (String) The shortname of the user that will be used as the IBM MQ administrator in interactions with a queue manager for this service instance. + * Constraints: The maximum length is `12` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z][-a-z0-9]*$/`. + diff --git a/website/docs/guides/custom-service-endpoints.html.md b/website/docs/guides/custom-service-endpoints.html.md index ac2a9ebe5d..b03eedc00b 100644 --- a/website/docs/guides/custom-service-endpoints.html.md +++ b/website/docs/guides/custom-service-endpoints.html.md @@ -14,10 +14,14 @@ The IBM Cloud Provider plug-in for Terraform can be configured to use non-defaul -- [Getting Started with custom service endpoints](#getting-started-with-custom-service-endpoints) -- [Supported endpoint customizations](#supported-endpoint-customizations) -- [File structure for endpoints file](#file-structure-for-endpoints-file) -- [Prioritisation of endpoints](#prioritisation-of-endpoints) +- [Customizing default cloud service endpoints](#customizing-default-cloud-service-endpoints) + - [Getting started with custom service endpoints](#getting-started-with-custom-service-endpoints) + - [Supported endpoint customizations](#supported-endpoint-customizations) + - [File structure for endpoints file](#file-structure-for-endpoints-file) + - [Prioritisation of endpoints](#prioritisation-of-endpoints) + - [1. Define service endpoints by using environment variables](#1-define-service-endpoints-by-using-environment-variables) + - [2. Define service endpoints by using an endpoints file](#2-define-service-endpoints-by-using-an-endpoints-file) + - [3. Use the default private or public service endpoint based on the `visibility` setting in the provider block](#3-use-the-default-private-or-public-service-endpoint-based-on-the-visibility-setting-in-the-provider-block) ## Getting started with custom service endpoints @@ -53,6 +57,7 @@ provider "ibm" { |Container Registry|IBMCLOUD_CR_API_ENDPOINT| |Kubernetes Service|IBMCLOUD_CS_API_ENDPOINT| |Metrics Router| IBMCLOUD_METRICS_ROUTING_API_ENDPOINT| +|MQ on Cloud| IBMCLOUD_MQCLOUD_CONFIG_ENDPOINT| |Direct Link|IBMCLOUD_DL_API_ENDPOINT| |Direct Link Provider|IBMCLOUD_DL_PROVIDER_API_ENDPOINT| |Enterprise Management|IBMCLOUD_ENTERPRISE_API_ENDPOINT| diff --git a/website/docs/r/mqcloud_application.html.markdown b/website/docs/r/mqcloud_application.html.markdown new file mode 100644 index 0000000000..a244325ade --- /dev/null +++ b/website/docs/r/mqcloud_application.html.markdown @@ -0,0 +1,55 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_mqcloud_application" +description: |- + Manages mqcloud_application. +subcategory: "MQ on Cloud" +--- + +# ibm_mqcloud_application + +Create, update, and delete mqcloud_applications with this resource. + +## Example Usage + +```hcl +resource "ibm_mqcloud_application" "mqcloud_application_instance" { + name = "test-app" + service_instance_guid = var.service_instance_guid +} +``` + +## Argument Reference + +You can specify the following arguments for this resource. + +* `name` - (Required, Forces new resource, String) The name of the application - conforming to MQ rules. + * Constraints: The maximum length is `12` characters. The minimum length is `1` character. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQ on Cloud service instance. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/`. + +## Attribute Reference + +After your resource is created, you can read values from the listed arguments and the following attributes. + +* `id` - The unique identifier of the mqcloud_application. +* `application_id` - (String) The ID of the application which was allocated on creation, and can be used for delete calls. +* `create_api_key_uri` - (String) The URI to create a new apikey for the application. +* `href` - (String) The URL for this application. + + +## Import + +You can import the `ibm_mqcloud_application` resource by using `id`. +The `id` property can be formed from `service_instance_guid`, and `application_id` in the following format: + +
+<service_instance_guid>/<application_id>
+
+* `service_instance_guid`: A string in the format `a2b4d4bc-dadb-4637-bcec-9b7d1e723af8`. The GUID that uniquely identifies the MQ on Cloud service instance. +* `application_id`: A string. The ID of the application which was allocated on creation, and can be used for delete calls. + +# Syntax +
+$ terraform import ibm_mqcloud_application.mqcloud_application <service_instance_guid>/<application_id>
+
diff --git a/website/docs/r/mqcloud_keystore_certificate.html.markdown b/website/docs/r/mqcloud_keystore_certificate.html.markdown new file mode 100644 index 0000000000..e3b1a0108c --- /dev/null +++ b/website/docs/r/mqcloud_keystore_certificate.html.markdown @@ -0,0 +1,73 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_mqcloud_keystore_certificate" +description: |- + Manages mqcloud_keystore_certificate. +subcategory: "MQ on Cloud" +--- + +# ibm_mqcloud_keystore_certificate + +Create, update, and delete mqcloud_keystore_certificates with this resource. + +## Example Usage + +```hcl +resource "ibm_mqcloud_keystore_certificate" "mqcloud_keystore_certificate_instance" { + label = "label" + queue_manager_id = var.queue_manager_id + service_instance_guid = var.service_instance_guid +} +``` + +## Argument Reference + +You can specify the following arguments for this resource. + +* `label` - (Required, Forces new resource, String) Certificate label in queue manager store. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9_.]*$/`. +* `queue_manager_id` - (Required, Forces new resource, String) The id of the queue manager to retrieve its full details. + * Constraints: The maximum length is `32` characters. The minimum length is `32` characters. The value must match regular expression `/^[0-9a-fA-F]{32}$/`. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQ on Cloud service instance. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/`. + +## Attribute Reference + +After your resource is created, you can read values from the listed arguments and the following attributes. + +* `id` - The unique identifier of the mqcloud_keystore_certificate. +* `certificate_id` - (String) ID of the certificate. + * Constraints: The maximum length is `16` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9a-fA-F]*$/`. +* `certificate_type` - (String) The type of certificate. + * Constraints: Allowable values are: `key_store`. +* `dns_names` - (List) The list of DNS names. + * Constraints: The maximum length is `200` items. The minimum length is `0` items. +* `dns_names_total_count` - (Integer) The total count of dns names. +* `expiry` - (String) Expiry date for the certificate. +* `fingerprint_sha256` - (String) Fingerprint SHA256. + * Constraints: The value must match regular expression `/^[A-F0-9]{2}(:[A-F0-9]{2}){31}$/`. +* `href` - (String) The URL for this key store certificate. +* `is_default` - (Boolean) Indicates whether it is the queue manager's default certificate. +* `issued` - (String) Date certificate was issued. +* `issuer_cn` - (String) Issuer's Common Name. +* `issuer_dn` - (String) Issuer's Distinguished Name. +* `subject_cn` - (String) Subject's Common Name. +* `subject_dn` - (String) Subject's Distinguished Name. + + +## Import + +You can import the `ibm_mqcloud_keystore_certificate` resource by using `id`. +The `id` property can be formed from `service_instance_guid`, `queue_manager_id`, and `certificate_id` in the following format: + +
+<service_instance_guid>/<queue_manager_id>/<certificate_id>
+
+* `service_instance_guid`: A string in the format `a2b4d4bc-dadb-4637-bcec-9b7d1e723af8`. The GUID that uniquely identifies the MQ on Cloud service instance. +* `queue_manager_id`: A string in the format `b8e1aeda078009cf3db74e90d5d42328`. The id of the queue manager to retrieve its full details. +* `certificate_id`: A string. ID of the certificate. + +# Syntax +
+$ terraform import ibm_mqcloud_keystore_certificate.mqcloud_keystore_certificate <service_instance_guid>/<queue_manager_id>/<certificate_id>
+
diff --git a/website/docs/r/mqcloud_queue_manager.html.markdown b/website/docs/r/mqcloud_queue_manager.html.markdown new file mode 100644 index 0000000000..b26b62631e --- /dev/null +++ b/website/docs/r/mqcloud_queue_manager.html.markdown @@ -0,0 +1,74 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_mqcloud_queue_manager" +description: |- + Manages mqcloud_queue_manager. +subcategory: "MQ on Cloud" +--- + +# ibm_mqcloud_queue_manager + +Create, update, and delete mqcloud_queue_managers with this resource. + +## Example Usage + +```hcl +resource "ibm_mqcloud_queue_manager" "mqcloud_queue_manager_instance" { + display_name = "A test queue manager" + location = "reserved-eu-fr-cluster-f884" + name = "testqm" + service_instance_guid = var.service_instance_guid + size = "lite" + version = "9.3.2_2" +} +``` + +## Argument Reference + +You can specify the following arguments for this resource. + +* `display_name` - (Optional, String) A displayable name for the queue manager - limited only in length. + * Constraints: The maximum length is `150` characters. +* `location` - (Required, String) The locations in which the queue manager could be deployed. + * Constraints: The maximum length is `150` characters. The minimum length is `2` characters. The value must match regular expression `/^([^[:ascii:]]|[a-zA-Z0-9-._: ])+$/`. +* `name` - (Required, String) A queue manager name conforming to MQ restrictions. + * Constraints: The maximum length is `48` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9._]*$/`. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQ on Cloud service instance. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/`. +* `size` - (Required, String) The queue manager sizes of deployment available. Deployment of lite queue managers for aws_us_east_1 and aws_eu_west_1 locations is not available. + * Constraints: Allowable values are: `lite`, `xsmall`, `small`, `medium`, `large`. +* `version` - (Optional, String) The MQ version of the queue manager. + * Constraints: The maximum length is `15` characters. The minimum length is `7` characters. The value must match regular expression `/^[0-9]+.[0-9]+.[0-9]+_[0-9]+$/`. + +## Attribute Reference + +After your resource is created, you can read values from the listed arguments and the following attributes. + +* `id` - The unique identifier of the mqcloud_queue_manager. +* `administrator_api_endpoint_url` - (String) The url through which to access the Admin REST APIs for this queue manager. +* `available_upgrade_versions_uri` - (String) The uri through which the available versions to upgrade to can be found for this queue manager. +* `connection_info_uri` - (String) The uri through which the CDDT for this queue manager can be obtained. +* `date_created` - (String) RFC3339 formatted UTC date for when the queue manager was created. +* `href` - (String) The URL for this queue manager. +* `queue_manager_id` - (String) The ID of the queue manager which was allocated on creation, and can be used for delete calls. +* `rest_api_endpoint_url` - (String) The url through which to access REST APIs for this queue manager. +* `status_uri` - (String) A reference uri to get deployment status of the queue manager. +* `upgrade_available` - (Boolean) Describes whether an upgrade is available for this queue manager. +* `web_console_url` - (String) The url through which to access the web console for this queue manager. + + +## Import + +You can import the `ibm_mqcloud_queue_manager` resource by using `id`. +The `id` property can be formed from `service_instance_guid`, and `queue_manager_id` in the following format: + +
+<service_instance_guid>/<queue_manager_id>
+
+* `service_instance_guid`: A string in the format `a2b4d4bc-dadb-4637-bcec-9b7d1e723af8`. The GUID that uniquely identifies the MQ on Cloud service instance. +* `queue_manager_id`: A string. The ID of the queue manager which was allocated on creation, and can be used for delete calls. + +# Syntax +
+$ terraform import ibm_mqcloud_queue_manager.mqcloud_queue_manager <service_instance_guid>/<queue_manager_id>
+
diff --git a/website/docs/r/mqcloud_truststore_certificate.html.markdown b/website/docs/r/mqcloud_truststore_certificate.html.markdown new file mode 100644 index 0000000000..ebc00ef103 --- /dev/null +++ b/website/docs/r/mqcloud_truststore_certificate.html.markdown @@ -0,0 +1,70 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_mqcloud_truststore_certificate" +description: |- + Manages mqcloud_truststore_certificate. +subcategory: "MQ on Cloud" +--- + +# ibm_mqcloud_truststore_certificate + +Create, update, and delete mqcloud_truststore_certificates with this resource. + +## Example Usage + +```hcl +resource "ibm_mqcloud_truststore_certificate" "mqcloud_truststore_certificate_instance" { + label = "label" + queue_manager_id = var.queue_manager_id + service_instance_guid = var.service_instance_guid +} +``` + +## Argument Reference + +You can specify the following arguments for this resource. + +* `label` - (Required, Forces new resource, String) Certificate label in queue manager store. + * Constraints: The maximum length is `64` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z0-9_.]*$/`. +* `queue_manager_id` - (Required, Forces new resource, String) The id of the queue manager to retrieve its full details. + * Constraints: The maximum length is `32` characters. The minimum length is `32` characters. The value must match regular expression `/^[0-9a-fA-F]{32}$/`. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQ on Cloud service instance. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/`. + +## Attribute Reference + +After your resource is created, you can read values from the listed arguments and the following attributes. + +* `id` - The unique identifier of the mqcloud_truststore_certificate. +* `certificate_id` - (String) Id of the certificate. + * Constraints: The maximum length is `16` characters. The minimum length is `1` character. The value must match regular expression `/^[0-9a-fA-F]*$/`. +* `certificate_type` - (String) The type of certificate. + * Constraints: Allowable values are: `trust_store`. +* `expiry` - (String) Expiry date for the certificate. +* `fingerprint_sha256` - (String) Fingerprint SHA256. + * Constraints: The value must match regular expression `/^[A-F0-9]{2}(:[A-F0-9]{2}){31}$/`. +* `href` - (String) The URL for this trust store certificate. +* `issued` - (String) The Date the certificate was issued. +* `issuer_cn` - (String) Issuer's Common Name. +* `issuer_dn` - (String) Issuer's Distinguished Name. +* `subject_cn` - (String) Subject's Common Name. +* `subject_dn` - (String) Subject's Distinguished Name. +* `trusted` - (Boolean) Indicates whether a certificate is trusted. + + +## Import + +You can import the `ibm_mqcloud_truststore_certificate` resource by using `id`. +The `id` property can be formed from `service_instance_guid`, `queue_manager_id`, and `certificate_id` in the following format: + +
+<service_instance_guid>/<queue_manager_id>/<certificate_id>
+
+* `service_instance_guid`: A string in the format `a2b4d4bc-dadb-4637-bcec-9b7d1e723af8`. The GUID that uniquely identifies the MQ on Cloud service instance. +* `queue_manager_id`: A string in the format `b8e1aeda078009cf3db74e90d5d42328`. The id of the queue manager to retrieve its full details. +* `certificate_id`: A string. Id of the certificate. + +# Syntax +
+$ terraform import ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate <service_instance_guid>/<queue_manager_id>/<certificate_id>
+
diff --git a/website/docs/r/mqcloud_user.html.markdown b/website/docs/r/mqcloud_user.html.markdown new file mode 100644 index 0000000000..6d12da2ab7 --- /dev/null +++ b/website/docs/r/mqcloud_user.html.markdown @@ -0,0 +1,57 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_mqcloud_user" +description: |- + Manages mqcloud_user. +subcategory: "MQ on Cloud" +--- + +# ibm_mqcloud_user + +Create, update, and delete mqcloud_users with this resource. + +## Example Usage + +```hcl +resource "ibm_mqcloud_user" "mqcloud_user_instance" { + email = "user@example.com" + name = "t0scie98o57a" + service_instance_guid = var.service_instance_guid +} +``` + +## Argument Reference + +You can specify the following arguments for this resource. + +* `email` - (Required, Forces new resource, String) The email of the user. + * Constraints: The maximum length is `253` characters. The minimum length is `5` characters. +* `name` - (Required, Forces new resource, String) The shortname of the user that will be used as the IBM MQ administrator in interactions with a queue manager for this service instance. + * Constraints: The maximum length is `12` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z][-a-z0-9]*$/`. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQ on Cloud service instance. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/`. + +## Attribute Reference + +After your resource is created, you can read values from the listed arguments and the following attributes. + +* `id` - The unique identifier of the mqcloud_user. +* `href` - (String) The URL for the user details. +* `user_id` - (String) The ID of the user which was allocated on creation, and can be used for delete calls. + + +## Import + +You can import the `ibm_mqcloud_user` resource by using `id`. +The `id` property can be formed from `service_instance_guid`, and `user_id` in the following format: + +
+<service_instance_guid>/<user_id>
+
+* `service_instance_guid`: A string in the format `a2b4d4bc-dadb-4637-bcec-9b7d1e723af8`. The GUID that uniquely identifies the MQ on Cloud service instance. +* `user_id`: A string. The ID of the user which was allocated on creation, and can be used for delete calls. + +# Syntax +
+$ terraform import ibm_mqcloud_user.mqcloud_user <service_instance_guid>/<user_id>
+
From d98953da552351a566d19a3106ad6f422d2eafb8 Mon Sep 17 00:00:00 2001 From: yonatanyell <69857977+yonatanyell@users.noreply.github.com> Date: Wed, 13 Dec 2023 09:04:15 +0200 Subject: [PATCH 10/14] Service Credentials secret addition (#4926) * SC addition * SC addition * SC addition * update function updated * SC unit tests added * SC unit tests added * d * tests fixes * tests fixes * update sdk * .secrets.baseline update * .secrets.baseline update * .secrets.baseline update * Update sm_service_credentials_secret_metadata.html.markdown --------- Co-authored-by: Yonathan-Yellin Co-authored-by: Avi Ribchinsky Co-authored-by: Tatyana Co-authored-by: Idan Adar --- .secrets.baseline | 80 +- examples/ibm-secrets-manager/README.md | 238 +++--- examples/ibm-secrets-manager/main.tf | 43 + examples/ibm-secrets-manager/outputs.tf | 6 + examples/ibm-secrets-manager/variables.tf | 63 ++ go.mod | 2 +- go.sum | 4 +- ibm/acctest/acctest.go | 6 + ibm/provider/provider.go | 3 + ...ource_ibm_sm_service_credentials_secret.go | 506 +++++++++++ ..._sm_service_credentials_secret_metadata.go | 494 +++++++++++ ...ervice_credentials_secret_metadata_test.go | 74 ++ ..._ibm_sm_service_credentials_secret_test.go | 83 ++ ...ource_ibm_sm_service_credentilas_secret.go | 790 ++++++++++++++++++ ..._ibm_sm_service_credentilas_secret_test.go | 335 ++++++++ ibm/service/secretsmanager/utils.go | 15 +- ...m_service_credentials_secret.html.markdown | 156 ++++ ..._credentials_secret_metadata.html.markdown | 113 +++ ...m_service_credentials_secret.html.markdown | 222 +++++ 19 files changed, 3119 insertions(+), 114 deletions(-) create mode 100644 ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret.go create mode 100644 ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret_metadata.go create mode 100644 ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret_metadata_test.go create mode 100644 ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret_test.go create mode 100644 ibm/service/secretsmanager/resource_ibm_sm_service_credentilas_secret.go create mode 100644 ibm/service/secretsmanager/resource_ibm_sm_service_credentilas_secret_test.go create mode 100644 website/docs/d/sm_service_credentials_secret.html.markdown create mode 100644 website/docs/d/sm_service_credentials_secret_metadata.html.markdown create mode 100644 website/docs/r/sm_service_credentials_secret.html.markdown diff --git a/.secrets.baseline b/.secrets.baseline index f846664a78..dfa3b8db5b 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "go.mod|go.sum|.*.map|^.secrets.baseline$", "lines": null }, - "generated_at": "2023-12-11T01:02:37Z", + "generated_at": "2023-12-11T16:26:19Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -696,7 +696,7 @@ "hashed_secret": "912accc17209bb36cb22d76d430ef9e9ec99dd4c", "is_secret": false, "is_verified": false, - "line_number": 163, + "line_number": 188, "type": "Secret Keyword", "verified_result": null }, @@ -704,7 +704,7 @@ "hashed_secret": "514edd121688f936809a62aecd24419c7eaa772b", "is_secret": false, "is_verified": false, - "line_number": 250, + "line_number": 275, "type": "Secret Keyword", "verified_result": null }, @@ -712,7 +712,7 @@ "hashed_secret": "fa33d07da58b52eee9f13b88e9cda8b98f1c19b6", "is_secret": false, "is_verified": false, - "line_number": 261, + "line_number": 286, "type": "Secret Keyword", "verified_result": null }, @@ -720,7 +720,7 @@ "hashed_secret": "5926151b9a84e25fbc262e88ef6c1d58f0c95548", "is_secret": false, "is_verified": false, - "line_number": 273, + "line_number": 298, "type": "Secret Keyword", "verified_result": null } @@ -776,7 +776,7 @@ "hashed_secret": "813274ccae5b6b509379ab56982d862f7b5969b6", "is_secret": false, "is_verified": false, - "line_number": 1134, + "line_number": 1128, "type": "Base64 High Entropy String", "verified_result": null } @@ -864,7 +864,7 @@ "hashed_secret": "c8b6f5ef11b9223ac35a5663975a466ebe7ebba9", "is_secret": false, "is_verified": false, - "line_number": 1807, + "line_number": 1806, "type": "Secret Keyword", "verified_result": null }, @@ -872,7 +872,7 @@ "hashed_secret": "8abf4899c01104241510ba87685ad4de76b0c437", "is_secret": false, "is_verified": false, - "line_number": 1813, + "line_number": 1812, "type": "Secret Keyword", "verified_result": null } @@ -3453,6 +3453,34 @@ "verified_result": null } ], + "ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret.go": [ + { + "hashed_secret": "3046d9f6cfaaeea6eed9bb7a4ab010fe49b0cfd4", + "is_secret": false, + "is_verified": false, + "line_number": 196, + "type": "Secret Keyword", + "verified_result": null + }, + { + "hashed_secret": "b732fb611fd46a38e8667f9972e0cde777fbe37f", + "is_secret": false, + "is_verified": false, + "line_number": 387, + "type": "Secret Keyword", + "verified_result": null + } + ], + "ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret_metadata.go": [ + { + "hashed_secret": "3046d9f6cfaaeea6eed9bb7a4ab010fe49b0cfd4", + "is_secret": false, + "is_verified": false, + "line_number": 179, + "type": "Secret Keyword", + "verified_result": null + } + ], "ibm/service/secretsmanager/data_source_ibm_sm_username_password_secret.go": [ { "hashed_secret": "3046d9f6cfaaeea6eed9bb7a4ab010fe49b0cfd4", @@ -3761,6 +3789,24 @@ "verified_result": null } ], + "ibm/service/secretsmanager/resource_ibm_sm_service_credentilas_secret.go": [ + { + "hashed_secret": "3046d9f6cfaaeea6eed9bb7a4ab010fe49b0cfd4", + "is_secret": false, + "is_verified": false, + "line_number": 190, + "type": "Secret Keyword", + "verified_result": null + }, + { + "hashed_secret": "b732fb611fd46a38e8667f9972e0cde777fbe37f", + "is_secret": false, + "is_verified": false, + "line_number": 443, + "type": "Secret Keyword", + "verified_result": null + } + ], "ibm/service/secretsmanager/resource_ibm_sm_username_password_secret.go": [ { "hashed_secret": "3046d9f6cfaaeea6eed9bb7a4ab010fe49b0cfd4", @@ -4909,6 +4955,24 @@ "verified_result": null } ], + "website/docs/r/sm_service_credentials_secret.html.markdown": [ + { + "hashed_secret": "d47dcacc720a39e236679ac3e311a0d58bb6519e", + "is_secret": false, + "is_verified": false, + "line_number": 191, + "type": "Secret Keyword", + "verified_result": null + }, + { + "hashed_secret": "e66e7d67fdf3c596c435fc7828b13205e4950a0f", + "is_secret": false, + "is_verified": false, + "line_number": 193, + "type": "Secret Keyword", + "verified_result": null + } + ], "website/docs/r/sm_username_password_secret.html.markdown": [ { "hashed_secret": "e3efaa78f2f6ca38f70ded91b232d8dac947315d", diff --git a/examples/ibm-secrets-manager/README.md b/examples/ibm-secrets-manager/README.md index 04a144758a..f68677dec5 100644 --- a/examples/ibm-secrets-manager/README.md +++ b/examples/ibm-secrets-manager/README.md @@ -131,6 +131,31 @@ resource "sm_iam_credentials_secret" "sm_iam_credentials_secret_instance" { rotation = var.sm_iam_credentials_secret_rotation } ``` +sm_service_credentials_secret resource: + +```hcl +resource "ibm_sm_service_credentials_secret" "sm_service_credentials_secret" { + instance_id = var.secrets_manager_instance_id + region = var.region + endpoint_type = var.endpoint_type + name = var.sm_service_credentials_secret_name + custom_metadata = { my_key = jsonencode(var.sm_service_credentials_secret_custom_metadata) } + description = var.sm_service_credentials_secret_description + labels = var.sm_service_credentials_secret_labels + rotation = var.sm_service_credentials_secret_rotation + secret_group_id = var.sm_service_credentials_secret_secret_group_id + source_service { + instance { + crn = var.sm_service_credentials_secret_source_service_instance_crn + } + role { + crn = var.sm_service_credentials_secret_source_service_role_crn + } + parameters = var.sm_service_credentials_secret_source_service_parameters + } + ttl = var.sm_service_credentials_secret_ttl +} +``` sm_arbitrary_secret resource: ```hcl @@ -349,6 +374,15 @@ data "sm_iam_credentials_secret_metadata" "sm_iam_credentials_secret_metadata_in secret_id = var.sm_iam_credentials_secret_metadata_id } ``` +sm_service_credentials_secret_metadata data source: + +```hcl +data "sm_service_credentials_secret_metadata" "sm_service_credentials_secret_metadata_instance" { + instance_id = var.secrets_manager_instance_id + region = var.region + secret_id = var.sm_service_credentials_secret_metadata_id +} +``` sm_arbitrary_secret_metadata data source: ```hcl @@ -403,6 +437,15 @@ data "sm_iam_credentials_secret" "sm_iam_credentials_secret_instance" { secret_id = var.sm_iam_credentials_secret_id } ``` +sm_service_credentials_secret data source: + +```hcl +data "sm_service_credentials_secret" "sm_service_credentials_secret_instance" { + instance_id = var.secrets_manager_instance_id + region = var.region + secret_id = var.sm_service_credentials_secret_id +} +``` sm_arbitrary_secret data source: ```hcl @@ -524,103 +567,106 @@ data "sm_en_registration" "sm_en_registration_instance" { ## Inputs -| Name | Description | Type | Default | Required | -|----------------------------------------|-------------|------|---------|----------| -| ibmcloud\_api\_key | IBM Cloud API key | `string` | | true | -| region | Secrets Manager Instance region | `string` | us-south | false | -| secrets\_manager\_instance\_id | Secrets Manager Instance GUID | `string` | | true | -| instance\_id | Secrets Manager Instance GUID | `string` | | true | -| endpoint\_type | Secrets manager endpoint type | `string` | `private` | false | -| description | An extended description of your secret group.To protect your privacy, do not use personal data, such as your name or location, as a description for your secret group. | `string` | false | -| custom_metadata | The secret metadata that a user can customize. | `map()` | false | -| description | An extended description of your secret.To protect your privacy, do not use personal data, such as your name or location, as a description for your secret group. | `string` | false | -| expiration_date | The date a secret is expired. The date format follows RFC 3339. | `` | false | -| labels | Labels that you can use to search for secrets in your instance.Up to 30 labels can be created. | `list(string)` | false | -| secret_group_id | A v4 UUID identifier, or `default` secret group. | `string` | false | -| secret_type | The secret type. Supported types are arbitrary, certificates (imported, public, and private), IAM credentials, key-value, and user credentials. | `string` | false | -| certificate | The PEM-encoded contents of your certificate. | `string` | false | -| intermediate | (Optional) The PEM-encoded intermediate certificate to associate with the root certificate. | `string` | false | -| private_key | (Optional) The PEM-encoded private key to associate with the certificate. | `string` | false | -| custom_metadata | The secret metadata that a user can customize. | `map()` | false | -| rotation | Determines whether Secrets Manager rotates your secrets automatically. | `` | false | -| data | The payload data of a key-value secret. | `map()` | false | -| ttl | The time-to-live (TTL) or lease duration to assign to generated credentials.For `iam_credentials` secrets, the TTL defines for how long each generated API key remains valid. The value can be either an integer that specifies the number of seconds, or the string representation of a duration, such as `120m` or `24h`.Minimum duration is 1 minute. Maximum is 90 days. | `string` | false | -| access_groups | Access Groups that you can use for an `iam_credentials` secret.Up to 10 Access Groups can be used for each secret. | `list(string)` | false | -| service_id | The service ID under which the API key (see the `api_key` field) is created.If you omit this parameter, Secrets Manager generates a new service ID for your secret at its creation and adds it to the access groups that you assign.Optionally, you can use this field to provide your own service ID if you prefer to manage its access directly or retain the service ID after your secret expires, is rotated, or deleted. If you provide a service ID, do not include the `access_groups` parameter. | `string` | false | -| reuse_api_key | Determines whether to use the same service ID and API key for future read operations on an`iam_credentials` secret.If it is set to `true`, the service reuses the current credentials. If it is set to `false`, a new service ID and API key are generated each time that the secret is read or accessed. | `bool` | false | -| payload | The arbitrary secret's data payload. | `string` | false | -| username | The username that is assigned to the secret. | `string` | false | -| password | The password that is assigned to the secret. | `string` | false | -| secret_id | The ID of the secret. | `string` | true | -| certificate_template | The name of the certificate template. | `string` | false | -| config_type | Th configuration type. | `string` | false | -| crl_disable | Disables or enables certificate revocation list (CRL) building.If CRL building is disabled, a signed but zero-length CRL is returned when downloading the CRL. If CRL building is enabled, it will rebuild the CRL. | `bool` | false | -| crl_distribution_points_encoded | Determines whether to encode the certificate revocation list (CRL) distribution points in the certificates that are issued by this certificate authority. | `bool` | false | -| issuing_certificates_urls_encoded | Determines whether to encode the URL of the issuing certificate in the certificates that are issued by this certificate authority. | `bool` | false | -| ttl | The requested time-to-live (TTL) for certificates that are created by this CA. This field's value cannot be longer than the `max_ttl` limit.The value can be supplied as a string representation of a duration in hours, for example '8760h'. In the API response, this value is returned in seconds (integer). | `string` | false | -| signing_method | The signing method to use with this certificate authority to generate private certificates.You can choose between internal or externally signed options. For more information, see the [docs](https://cloud.ibm.com/docs/secrets-manager?topic=secrets-manager-intermediate-certificate-authorities). | `string` | false | -| certificate_authority | The name of the intermediate certificate authority. | `string` | false | -| allowed_secret_groups | Scopes the creation of private certificates to only the secret groups that you specify.This field can be supplied as a comma-delimited list of secret group IDs. | `string` | false | -| allow_localhost | Determines whether to allow `localhost` to be included as one of the requested common names. | `bool` | false | -| allowed_domains | The domains to define for the certificate template. This property is used along with the `allow_bare_domains` and `allow_subdomains` options. | `list(string)` | false | -| allowed_domains_template | Determines whether to allow the domains that are supplied in the `allowed_domains` field to contain access control list (ACL) templates. | `bool` | false | -| allow_bare_domains | Determines whether to allow clients to request private certificates that match the value of the actual domains on the final certificate.For example, if you specify `example.com` in the `allowed_domains` field, you grant clients the ability to request a certificate that contains the name `example.com` as one of the DNS values on the final certificate.**Important:** In some scenarios, allowing bare domains can be considered a security risk. | `bool` | false | -| allow_subdomains | Determines whether to allow clients to request private certificates with common names (CN) that are subdomains of the CNs that are allowed by the other certificate template options. This includes wildcard subdomains.For example, if `allowed_domains` has a value of `example.com` and `allow_subdomains`is set to `true`, then the following subdomains are allowed: `foo.example.com`, `bar.example.com`, `*.example.com`.**Note:** This field is redundant if you use the `allow_any_name` option. | `bool` | false | -| allow_glob_domains | Determines whether to allow glob patterns, for example, `ftp*.example.com`, in the names that are specified in the `allowed_domains` field.If set to `true`, clients are allowed to request private certificates with names that match the glob patterns. | `bool` | false | -| allow_any_name | Determines whether to allow clients to request a private certificate that matches any common name. | `bool` | false | -| enforce_hostnames | Determines whether to enforce only valid host names for common names, DNS Subject Alternative Names, and the host section of email addresses. | `bool` | false | -| allow_ip_sans | Determines whether to allow clients to request a private certificate with IP Subject Alternative Names. | `bool` | false | -| allowed_uri_sans | The URI Subject Alternative Names to allow for private certificates.Values can contain glob patterns, for example `spiffe://hostname/_*`. | `list(string)` | false | -| allowed_other_sans | The custom Object Identifier (OID) or UTF8-string Subject Alternative Names (SANs) to allow for private certificates.The format for each element in the list is the same as OpenSSL: `::` where the current valid type is `UTF8`. To allow any value for an OID, use `*` as its value. Alternatively, specify a single `*` to allow any `other_sans` input. | `list(string)` | false | -| server_flag | Determines whether private certificates are flagged for server use. | `bool` | false | -| client_flag | Determines whether private certificates are flagged for client use. | `bool` | false | -| code_signing_flag | Determines whether private certificates are flagged for code signing use. | `bool` | false | -| email_protection_flag | Determines whether private certificates are flagged for email protection use. | `bool` | false | -| key_usage | The allowed key usage constraint to define for private certificates.You can find valid values in the [Go x509 package documentation](https://pkg.go.dev/crypto/x509#KeyUsage). Omit the `KeyUsage` part of the value. Values are not case-sensitive. To specify no key usage constraints, set this field to an empty list. | `list(string)` | false | -| ext_key_usage | The allowed extended key usage constraint on private certificates.You can find valid values in the [Go x509 package documentation](https://golang.org/pkg/crypto/x509/#ExtKeyUsage). Omit the `ExtKeyUsage` part of the value. Values are not case-sensitive. To specify no key usage constraints, set this field to an empty list. | `list(string)` | false | -| ext_key_usage_oids | A list of extended key usage Object Identifiers (OIDs). | `list(string)` | false | -| use_csr_common_name | When used with the `private_cert_configuration_action_sign_csr` action, this field determines whether to use the common name (CN) from a certificate signing request (CSR) instead of the CN that's included in the data of the certificate.Does not include any requested Subject Alternative Names (SANs) in the CSR. To use the alternative names, include the `use_csr_sans` property. | `bool` | false | -| use_csr_sans | When used with the `private_cert_configuration_action_sign_csr` action, this field determines whether to use the Subject Alternative Names(SANs) from a certificate signing request (CSR) instead of the SANs that are included in the data of the certificate.Does not include the common name in the CSR. To use the common name, include the `use_csr_common_name` property. | `bool` | false | -| require_cn | Determines whether to require a common name to create a private certificate.By default, a common name is required to generate a certificate. To make the `common_name` field optional, set the `require_cn` option to `false`. | `bool` | false | -| policy_identifiers | A list of policy Object Identifiers (OIDs). | `list(string)` | false | -| basic_constraints_valid_for_non_ca | Determines whether to mark the Basic Constraints extension of an issued private certificate as valid for non-CA certificates. | `bool` | false | -| lets_encrypt_environment | The configuration of the Let's Encrypt CA environment. | `string` | false | -| lets_encrypt_private_key | The PEM encoded private key of your Lets Encrypt account. | `string` | false | -| lets_encrypt_preferred_chain | Prefer the chain with an issuer matching this Subject Common Name. | `string` | false | -| event_notifications_instance_crn | A CRN that uniquely identifies an IBM Cloud resource. | `string` | true | -| event_notifications_source_name | The name that is displayed as a source that is in your Event Notifications instance. | `string` | true | -| event_notifications_source_description | An optional description for the source that is in your Event Notifications instance. | `string` | false | -| secret_group_id | The ID of the secret group. | `string` | true | -| secret_id | The ID of the secret. | `string` | true | -| name | The name of the configuration. | `string` | true | +| Name | Description | Type | Default | Required | +|----------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------|-----------|----------| +| ibmcloud\_api\_key | IBM Cloud API key | `string` | | true | +| region | Secrets Manager Instance region | `string` | us-south | false | +| secrets\_manager\_instance\_id | Secrets Manager Instance GUID | `string` | | true | +| instance\_id | Secrets Manager Instance GUID | `string` | | true | +| endpoint\_type | Secrets manager endpoint type | `string` | `private` | false | +| description | An extended description of your secret group.To protect your privacy, do not use personal data, such as your name or location, as a description for your secret group. | `string` | false | +| custom_metadata | The secret metadata that a user can customize. | `map()` | false | +| description | An extended description of your secret.To protect your privacy, do not use personal data, such as your name or location, as a description for your secret group. | `string` | false | +| expiration_date | The date a secret is expired. The date format follows RFC 3339. | `` | false | +| labels | Labels that you can use to search for secrets in your instance.Up to 30 labels can be created. | `list(string)` | false | +| secret_group_id | A v4 UUID identifier, or `default` secret group. | `string` | false | +| secret_type | The secret type. Supported types are arbitrary, certificates (imported, public, and private), IAM credentials, key-value, and user credentials. | `string` | false | +| certificate | The PEM-encoded contents of your certificate. | `string` | false | +| intermediate | (Optional) The PEM-encoded intermediate certificate to associate with the root certificate. | `string` | false | +| private_key | (Optional) The PEM-encoded private key to associate with the certificate. | `string` | false | +| custom_metadata | The secret metadata that a user can customize. | `map()` | false | +| rotation | Determines whether Secrets Manager rotates your secrets automatically. | `` | false | +| source_service | The properties required for creating the service credentials for the specified source service instance. | `` | false | +| data | The payload data of a key-value secret. | `map()` | false | +| ttl | The time-to-live (TTL) or lease duration to assign to generated credentials.The TTL defines for how long generated credentials remain valid. For iam_credentials secret TTL is mandatory. The minimum duration is 1 minute. The maximum is 90 days. For service_credentials secret TTL is optional, if set the minimum duration is 1 day. The maximum is 90 days. The TTL defaults to 0 which means no TTL. | `string` | false | +| access_groups | Access Groups that you can use for an `iam_credentials` secret.Up to 10 Access Groups can be used for each secret. | `list(string)` | false | +| service_id | The service ID under which the API key (see the `api_key` field) is created.If you omit this parameter, Secrets Manager generates a new service ID for your secret at its creation and adds it to the access groups that you assign.Optionally, you can use this field to provide your own service ID if you prefer to manage its access directly or retain the service ID after your secret expires, is rotated, or deleted. If you provide a service ID, do not include the `access_groups` parameter. | `string` | false | +| reuse_api_key | Determines whether to use the same service ID and API key for future read operations on an`iam_credentials` secret.If it is set to `true`, the service reuses the current credentials. If it is set to `false`, a new service ID and API key are generated each time that the secret is read or accessed. | `bool` | false | +| payload | The arbitrary secret's data payload. | `string` | false | +| username | The username that is assigned to the secret. | `string` | false | +| password | The password that is assigned to the secret. | `string` | false | +| secret_id | The ID of the secret. | `string` | true | +| certificate_template | The name of the certificate template. | `string` | false | +| config_type | Th configuration type. | `string` | false | +| crl_disable | Disables or enables certificate revocation list (CRL) building.If CRL building is disabled, a signed but zero-length CRL is returned when downloading the CRL. If CRL building is enabled, it will rebuild the CRL. | `bool` | false | +| crl_distribution_points_encoded | Determines whether to encode the certificate revocation list (CRL) distribution points in the certificates that are issued by this certificate authority. | `bool` | false | +| issuing_certificates_urls_encoded | Determines whether to encode the URL of the issuing certificate in the certificates that are issued by this certificate authority. | `bool` | false | +| ttl | The requested time-to-live (TTL) for certificates that are created by this CA. This field's value cannot be longer than the `max_ttl` limit.The value can be supplied as a string representation of a duration in hours, for example '8760h'. In the API response, this value is returned in seconds (integer). | `string` | false | +| signing_method | The signing method to use with this certificate authority to generate private certificates.You can choose between internal or externally signed options. For more information, see the [docs](https://cloud.ibm.com/docs/secrets-manager?topic=secrets-manager-intermediate-certificate-authorities). | `string` | false | +| certificate_authority | The name of the intermediate certificate authority. | `string` | false | +| allowed_secret_groups | Scopes the creation of private certificates to only the secret groups that you specify.This field can be supplied as a comma-delimited list of secret group IDs. | `string` | false | +| allow_localhost | Determines whether to allow `localhost` to be included as one of the requested common names. | `bool` | false | +| allowed_domains | The domains to define for the certificate template. This property is used along with the `allow_bare_domains` and `allow_subdomains` options. | `list(string)` | false | +| allowed_domains_template | Determines whether to allow the domains that are supplied in the `allowed_domains` field to contain access control list (ACL) templates. | `bool` | false | +| allow_bare_domains | Determines whether to allow clients to request private certificates that match the value of the actual domains on the final certificate.For example, if you specify `example.com` in the `allowed_domains` field, you grant clients the ability to request a certificate that contains the name `example.com` as one of the DNS values on the final certificate.**Important:** In some scenarios, allowing bare domains can be considered a security risk. | `bool` | false | +| allow_subdomains | Determines whether to allow clients to request private certificates with common names (CN) that are subdomains of the CNs that are allowed by the other certificate template options. This includes wildcard subdomains.For example, if `allowed_domains` has a value of `example.com` and `allow_subdomains`is set to `true`, then the following subdomains are allowed: `foo.example.com`, `bar.example.com`, `*.example.com`.**Note:** This field is redundant if you use the `allow_any_name` option. | `bool` | false | +| allow_glob_domains | Determines whether to allow glob patterns, for example, `ftp*.example.com`, in the names that are specified in the `allowed_domains` field.If set to `true`, clients are allowed to request private certificates with names that match the glob patterns. | `bool` | false | +| allow_any_name | Determines whether to allow clients to request a private certificate that matches any common name. | `bool` | false | +| enforce_hostnames | Determines whether to enforce only valid host names for common names, DNS Subject Alternative Names, and the host section of email addresses. | `bool` | false | +| allow_ip_sans | Determines whether to allow clients to request a private certificate with IP Subject Alternative Names. | `bool` | false | +| allowed_uri_sans | The URI Subject Alternative Names to allow for private certificates.Values can contain glob patterns, for example `spiffe://hostname/_*`. | `list(string)` | false | +| allowed_other_sans | The custom Object Identifier (OID) or UTF8-string Subject Alternative Names (SANs) to allow for private certificates.The format for each element in the list is the same as OpenSSL: `::` where the current valid type is `UTF8`. To allow any value for an OID, use `*` as its value. Alternatively, specify a single `*` to allow any `other_sans` input. | `list(string)` | false | +| server_flag | Determines whether private certificates are flagged for server use. | `bool` | false | +| client_flag | Determines whether private certificates are flagged for client use. | `bool` | false | +| code_signing_flag | Determines whether private certificates are flagged for code signing use. | `bool` | false | +| email_protection_flag | Determines whether private certificates are flagged for email protection use. | `bool` | false | +| key_usage | The allowed key usage constraint to define for private certificates.You can find valid values in the [Go x509 package documentation](https://pkg.go.dev/crypto/x509#KeyUsage). Omit the `KeyUsage` part of the value. Values are not case-sensitive. To specify no key usage constraints, set this field to an empty list. | `list(string)` | false | +| ext_key_usage | The allowed extended key usage constraint on private certificates.You can find valid values in the [Go x509 package documentation](https://golang.org/pkg/crypto/x509/#ExtKeyUsage). Omit the `ExtKeyUsage` part of the value. Values are not case-sensitive. To specify no key usage constraints, set this field to an empty list. | `list(string)` | false | +| ext_key_usage_oids | A list of extended key usage Object Identifiers (OIDs). | `list(string)` | false | +| use_csr_common_name | When used with the `private_cert_configuration_action_sign_csr` action, this field determines whether to use the common name (CN) from a certificate signing request (CSR) instead of the CN that's included in the data of the certificate.Does not include any requested Subject Alternative Names (SANs) in the CSR. To use the alternative names, include the `use_csr_sans` property. | `bool` | false | +| use_csr_sans | When used with the `private_cert_configuration_action_sign_csr` action, this field determines whether to use the Subject Alternative Names(SANs) from a certificate signing request (CSR) instead of the SANs that are included in the data of the certificate.Does not include the common name in the CSR. To use the common name, include the `use_csr_common_name` property. | `bool` | false | +| require_cn | Determines whether to require a common name to create a private certificate.By default, a common name is required to generate a certificate. To make the `common_name` field optional, set the `require_cn` option to `false`. | `bool` | false | +| policy_identifiers | A list of policy Object Identifiers (OIDs). | `list(string)` | false | +| basic_constraints_valid_for_non_ca | Determines whether to mark the Basic Constraints extension of an issued private certificate as valid for non-CA certificates. | `bool` | false | +| lets_encrypt_environment | The configuration of the Let's Encrypt CA environment. | `string` | false | +| lets_encrypt_private_key | The PEM encoded private key of your Lets Encrypt account. | `string` | false | +| lets_encrypt_preferred_chain | Prefer the chain with an issuer matching this Subject Common Name. | `string` | false | +| event_notifications_instance_crn | A CRN that uniquely identifies an IBM Cloud resource. | `string` | true | +| event_notifications_source_name | The name that is displayed as a source that is in your Event Notifications instance. | `string` | true | +| event_notifications_source_description | An optional description for the source that is in your Event Notifications instance. | `string` | false | +| secret_group_id | The ID of the secret group. | `string` | true | +| secret_id | The ID of the secret. | `string` | true | +| name | The name of the configuration. | `string` | true | ## Outputs -| Name | Description | -|------|-------------| -| secrets\_manager\_secrets | secrets\_manager\_secrets object | -| secrets\_manager\_secret | secrets\_manager\_secret object | -| sm_secret_group | sm_secret_group object | -| sm_imported_certificate | sm_imported_certificate object | -| sm_public_certificate | sm_public_certificate object | -| sm_kv_secret | sm_kv_secret object | -| sm_iam_credentials_secret | sm_iam_credentials_secret object | -| sm_arbitrary_secret | sm_arbitrary_secret object | -| sm_username_password_secret | sm_username_password_secret object | -| sm_private_certificate | sm_private_certificate object | -| sm_private_certificate_configuration_root_ca | sm_private_certificate_configuration_root_ca object | +| Name | Description | +|------------------------------------------------------|-------------------------------------------------------------| +| secrets\_manager\_secrets | secrets\_manager\_secrets object | +| secrets\_manager\_secret | secrets\_manager\_secret object | +| sm_secret_group | sm_secret_group object | +| sm_imported_certificate | sm_imported_certificate object | +| sm_public_certificate | sm_public_certificate object | +| sm_kv_secret | sm_kv_secret object | +| sm_iam_credentials_secret | sm_iam_credentials_secret object | +| sm_service_credentials_secret | sm_service_credentials_secret object | +| sm_arbitrary_secret | sm_arbitrary_secret object | +| sm_username_password_secret | sm_username_password_secret object | +| sm_private_certificate | sm_private_certificate object | +| sm_private_certificate_configuration_root_ca | sm_private_certificate_configuration_root_ca object | | sm_private_certificate_configuration_intermediate_ca | sm_private_certificate_configuration_intermediate_ca object | -| sm_private_certificate_configuration_template | sm_private_certificate_configuration_template object | -| sm_public_certificate_configuration_ca_lets_encrypt | sm_public_certificate_configuration_ca_lets_encrypt object | -| sm_en_registration | sm_en_registration object | -| sm_secret_group | sm_secret_group object | -| sm_secret_groups | sm_secret_groups object | -| sm_secrets | sm_secrets object | -| sm_imported_certificate_metadata | sm_imported_certificate_metadata object | -| sm_public_certificate_metadata | sm_public_certificate_metadata object | -| sm_kv_secret_metadata | sm_kv_secret_metadata object | -| sm_iam_credentials_secret_metadata | sm_iam_credentials_secret_metadata object | -| sm_arbitrary_secret_metadata | sm_arbitrary_secret_metadata object | -| sm_username_password_secret_metadata | sm_username_password_secret_metadata object | -| sm_private_certificate_metadata | sm_private_certificate_metadata object | -| sm_configurations | sm_configurations object | +| sm_private_certificate_configuration_template | sm_private_certificate_configuration_template object | +| sm_public_certificate_configuration_ca_lets_encrypt | sm_public_certificate_configuration_ca_lets_encrypt object | +| sm_en_registration | sm_en_registration object | +| sm_secret_group | sm_secret_group object | +| sm_secret_groups | sm_secret_groups object | +| sm_secrets | sm_secrets object | +| sm_imported_certificate_metadata | sm_imported_certificate_metadata object | +| sm_public_certificate_metadata | sm_public_certificate_metadata object | +| sm_kv_secret_metadata | sm_kv_secret_metadata object | +| sm_iam_credentials_secret_metadata | sm_iam_credentials_secret_metadata object | +| sm_service_credentials_secret_metadata | sm_service_credentials_secret_metadata object | +| sm_arbitrary_secret_metadata | sm_arbitrary_secret_metadata object | +| sm_username_password_secret_metadata | sm_username_password_secret_metadata object | +| sm_private_certificate_metadata | sm_private_certificate_metadata object | +| sm_configurations | sm_configurations object | diff --git a/examples/ibm-secrets-manager/main.tf b/examples/ibm-secrets-manager/main.tf index 1e1a89fccb..5823fb3fa6 100644 --- a/examples/ibm-secrets-manager/main.tf +++ b/examples/ibm-secrets-manager/main.tf @@ -81,6 +81,33 @@ resource "ibm_sm_iam_credentials_secret" "sm_iam_credentials_secret_instance" { } } +// Provision sm_service_credentials_secret resource instance +resource "ibm_sm_service_credentials_secret" "sm_service_credentials_secret" { + instance_id = var.secrets_manager_instance_id + region = var.region + endpoint_type = var.endpoint_type + name = var.sm_service_credentials_secret_name + custom_metadata = { my_key = jsonencode(var.sm_service_credentials_secret_custom_metadata) } + description = var.sm_service_credentials_secret_description + labels = var.sm_service_credentials_secret_labels + rotation { + auto_rotate = true + interval = 1 + unit = "day" + } + secret_group_id = var.sm_service_credentials_secret_secret_group_id + source_service { + instance { + crn = var.sm_service_credentials_secret_source_service_instance_crn + } + role { + crn = var.sm_service_credentials_secret_source_service_role_crn + } + parameters = var.sm_service_credentials_secret_source_service_parameters + } + ttl = var.sm_service_credentials_secret_ttl +} + // Provision sm_arbitrary_secret resource instance resource "ibm_sm_arbitrary_secret" "sm_arbitrary_secret_instance" { instance_id = var.secrets_manager_instance_id @@ -304,6 +331,14 @@ data "ibm_sm_iam_credentials_secret_metadata" "sm_iam_credentials_secret_metadat secret_id = var.sm_iam_credentials_secret_metadata_id } +// Create sm_service_credentials_secret_metadata data source +data "ibm_sm_service_credentials_secret_metadata" "sm_service_credentials_secret_metadata_instance" { + instance_id = var.secrets_manager_instance_id + region = var.region + endpoint_type = var.endpoint_type + secret_id = var.sm_service_credentials_secret_metadata_id +} + // Create sm_arbitrary_secret_metadata data source data "ibm_sm_arbitrary_secret_metadata" "sm_arbitrary_secret_metadata_instance" { instance_id = var.secrets_manager_instance_id @@ -352,6 +387,14 @@ data "ibm_sm_iam_credentials_secret" "sm_iam_credentials_secret_instance" { secret_id = var.sm_iam_credentials_secret_id } +// Create sm_service_credentials_secret data source +data "ibm_sm_service_credentials_secret" "sm_service_credentials_secret_instance" { + instance_id = var.secrets_manager_instance_id + region = var.region + endpoint_type = var.endpoint_type + secret_id = var.sm_service_credentials_secret_id +} + // Create sm_arbitrary_secret data source data "ibm_sm_arbitrary_secret" "sm_arbitrary_secret_instance" { instance_id = var.secrets_manager_instance_id diff --git a/examples/ibm-secrets-manager/outputs.tf b/examples/ibm-secrets-manager/outputs.tf index 9ea26978eb..9684c8c1eb 100644 --- a/examples/ibm-secrets-manager/outputs.tf +++ b/examples/ibm-secrets-manager/outputs.tf @@ -45,6 +45,12 @@ output "ibm_sm_iam_credentials_secret" { value = ibm_sm_iam_credentials_secret.sm_iam_credentials_secret_instance description = "sm_iam_credentials_secret resource instance" } +// This allows sm_service_credentials_secret data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed +output "ibm_sm_service_credentials_secret" { + value = ibm_sm_service_credentials_secret.sm_service_credentials_secret_instance + description = "sm_service_credentials_secret resource instance" +} // This allows sm_arbitrary_secret data to be referenced by other resources and the terraform CLI // Modify this if only certain data should be exposed output "ibm_sm_arbitrary_secret" { diff --git a/examples/ibm-secrets-manager/variables.tf b/examples/ibm-secrets-manager/variables.tf index 6c713285b8..fba28a2af8 100644 --- a/examples/ibm-secrets-manager/variables.tf +++ b/examples/ibm-secrets-manager/variables.tf @@ -210,6 +210,54 @@ variable "sm_iam_credentials_secret_reuse_api_key" { default = true } +// Resource arguments for sm_service_credentials_secret +variable "sm_service_credentials_name" { + description = "The human-readable name of your secret." + type = string + default = "my-service-credentials-secret" +} +variable "sm_service_credentials_secret_custom_metadata" { + description = "The secret metadata that a user can customize." + type = any + default = "anything as a string" +} +variable "sm_service_credentials_secret_description" { + description = "An extended description of your secret.To protect your privacy, do not use personal data, such as your name or location, as a description for your secret group." + type = string + default = "Extended description for this secret." +} +variable "sm_service_credentials_secret_labels" { + description = "Labels that you can use to search for secrets in your instance.Up to 30 labels can be created." + type = list(string) + default = [ "my-label" ] +} +variable "sm_service_credentials_secret_secret_group_id" { + description = "A v4 UUID identifier, or `default` secret group." + type = string + default = "default" +} +variable "sm_service_credentials_secret_source_service_instance_crn" { + description = "A CRN that uniquely identifies a service credentials source" + type = string + default = "crn:v1:staging:public:cloud-object-storage:global:a/111f5fb10986423e9saa8512f1db7e65:111133c8-49ea-41xe-8c40-122038246f5b::" +} +variable "sm_service_credentials_secret_source_service_role_crn" { + description = "The service-specific custom role object, CRN role is accepted. Refer to the service’s documentation for supported roles." + type = string + default = "crn:v1:bluemix:public:iam::::serviceRole:Writer" +} +variable "sm_service_credentials_secret_source_service_parameters" { + description = "Configuration options represented as key-value pairs. Service-defined options are used in the generation of credentials for some services." + type = string + default = {} +} +variable "sm_service_credentials_secret_ttl" { + description = "The time-to-live (TTL) or lease duration to assign to generated credentials. The TTL defines for how long generated credentials remain valid. The value should be a string that specifies the number of seconds. Minimum duration is 86400 (1 day). Maximum is 7776000 seconds (90 days)." + type = string + default = "86401" +} + + // Resource arguments for sm_arbitrary_secret variable "sm_arbitrary_secret_name" { description = "The human-readable name of your secret." @@ -705,6 +753,14 @@ variable "sm_iam_credentials_secret_metadata_id" { default = "0b5571f7-21e6-42b7-91c5-3f5ac9793a46" } +// Data source arguments for sm_service_credentials_secret_metadata +variable "sm_service_credentials_secret_metadata_id" { + description = "The ID of the secret." + type = string + default = "0b5571f7-21e6-42b7-91c5-3f5ac9793a46" +} + + // Data source arguments for sm_arbitrary_secret_metadata variable "sm_arbitrary_secret_metadata_id" { description = "The ID of the secret." @@ -747,6 +803,13 @@ variable "sm_iam_credentials_secret_id" { default = "0b5571f7-21e6-42b7-91c5-3f5ac9793a46" } +// Data source arguments for sm_service_credentials_secret +variable "sm_service_credentials_secret_id" { + description = "The ID of the secret." + type = string + default = "0b5571f7-21e6-42b7-91c5-3f5ac9793a46" +} + // Data source arguments for sm_arbitrary_secret variable "sm_arbitrary_secret_id" { description = "The ID of the secret." diff --git a/go.mod b/go.mod index f7c431a96b..d69e3df819 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/IBM/push-notifications-go-sdk v0.0.0-20210310100607-5790b96c47f5 github.com/IBM/scc-go-sdk/v5 v5.1.3 github.com/IBM/schematics-go-sdk v0.2.2 - github.com/IBM/secrets-manager-go-sdk/v2 v2.0.1 + github.com/IBM/secrets-manager-go-sdk/v2 v2.0.2 github.com/IBM/vpc-beta-go-sdk v0.6.0 github.com/IBM/vpc-go-sdk v0.43.0 github.com/ScaleFT/sshkeys v0.0.0-20200327173127-6142f742bca5 diff --git a/go.sum b/go.sum index 8df8dccea4..9ee7c97b82 100644 --- a/go.sum +++ b/go.sum @@ -172,8 +172,8 @@ github.com/IBM/scc-go-sdk/v5 v5.1.3 h1:8zqJx/HgChTlMaC21HzthIR4HbFkuJ3dR/D68254j github.com/IBM/scc-go-sdk/v5 v5.1.3/go.mod h1:YtAVlzq10bwR82QX4ZavhDIwa1s85RuVO9N/KmXVcuk= github.com/IBM/schematics-go-sdk v0.2.2 h1:8S3hoVLzF/ZRgWDaLqwHnLmZvlEBHCKgHszmMh7yD2E= github.com/IBM/schematics-go-sdk v0.2.2/go.mod h1:Tw2OSAPdpC69AxcwoyqcYYaGTTW6YpERF9uNEU+BFRQ= -github.com/IBM/secrets-manager-go-sdk/v2 v2.0.1 h1:0Ouu31RsuOLdH26oNsnPErEjctWTplLEIXxwExnTZT0= -github.com/IBM/secrets-manager-go-sdk/v2 v2.0.1/go.mod h1:jagqWmjZ0zUEqh5jdGB42ApSQS40fu2LWw6pdg8JJko= +github.com/IBM/secrets-manager-go-sdk/v2 v2.0.2 h1:+Svh1OmoFxMBnZQSOUtp2UUzrOGFsSQlE5TFL/ptJco= +github.com/IBM/secrets-manager-go-sdk/v2 v2.0.2/go.mod h1:WII+LS4VkQYykmq65NWSuPb5xGNvsqkcK1aCWZoU2x4= github.com/IBM/vpc-beta-go-sdk v0.6.0 h1:wfM3AcW3zOM3xsRtZ+EA6+sESlGUjQ6Yf4n5QQyz4uc= github.com/IBM/vpc-beta-go-sdk v0.6.0/go.mod h1:fzHDAQIqH/5yJmYsKodKHLcqxMDT+yfH6vZjdiw8CQA= github.com/IBM/vpc-go-sdk v0.43.0 h1:uy/qWIqETCXraUG2cq5sjScr6pZ79ZteY1v5iLUVQ3Q= diff --git a/ibm/acctest/acctest.go b/ibm/acctest/acctest.go index 4e563d0cb8..4968af4c8a 100644 --- a/ibm/acctest/acctest.go +++ b/ibm/acctest/acctest.go @@ -146,6 +146,7 @@ var ( SecretsManagerPublicCertificateCommonName string SecretsManagerValidateManualDnsCisZoneId string SecretsManagerImportedCertificatePathToCertificate string + SecretsManagerServiceCredentialsCosCrn string SecretsManagerSecretType string SecretsManagerSecretID string ) @@ -1227,6 +1228,11 @@ func init() { fmt.Println("[INFO] Set the environment variable SECRETS_MANAGER_IMPORTED_CERTIFICATE_PATH_TO_CERTIFICATE for testing imported certificate's tests, else tests fail if not set correctly") } + SecretsManagerServiceCredentialsCosCrn = os.Getenv("SECRETS_MANAGER_SERVICE_CREDENTIALS_COS_CRN") + if SecretsManagerServiceCredentialsCosCrn == "" { + fmt.Println("[INFO] Set the environment variable SECRETS_MANAGER_SERVICE_CREDENTIALS_COS_CRN for testing service credentials' tests, else tests fail if not set correctly") + } + SecretsManagerSecretType = os.Getenv("SECRETS_MANAGER_SECRET_TYPE") if SecretsManagerSecretType == "" { SecretsManagerSecretType = "username_password" diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go index c00464a12b..48915f7c9d 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -702,6 +702,7 @@ func Provider() *schema.Provider { "ibm_sm_public_certificate_metadata": secretsmanager.AddInstanceFields(secretsmanager.DataSourceIbmSmPublicCertificateMetadata()), "ibm_sm_private_certificate_metadata": secretsmanager.AddInstanceFields(secretsmanager.DataSourceIbmSmPrivateCertificateMetadata()), "ibm_sm_iam_credentials_secret_metadata": secretsmanager.AddInstanceFields(secretsmanager.DataSourceIbmSmIamCredentialsSecretMetadata()), + "ibm_sm_service_credentials_secret_metadata": secretsmanager.AddInstanceFields(secretsmanager.DataSourceIbmSmServiceCredentialsSecretMetadata()), "ibm_sm_kv_secret_metadata": secretsmanager.AddInstanceFields(secretsmanager.DataSourceIbmSmKvSecretMetadata()), "ibm_sm_username_password_secret_metadata": secretsmanager.AddInstanceFields(secretsmanager.DataSourceIbmSmUsernamePasswordSecretMetadata()), "ibm_sm_arbitrary_secret": secretsmanager.AddInstanceFields(secretsmanager.DataSourceIbmSmArbitrarySecret()), @@ -711,6 +712,7 @@ func Provider() *schema.Provider { "ibm_sm_iam_credentials_secret": secretsmanager.AddInstanceFields(secretsmanager.DataSourceIbmSmIamCredentialsSecret()), "ibm_sm_kv_secret": secretsmanager.AddInstanceFields(secretsmanager.DataSourceIbmSmKvSecret()), "ibm_sm_username_password_secret": secretsmanager.AddInstanceFields(secretsmanager.DataSourceIbmSmUsernamePasswordSecret()), + "ibm_sm_service_credentials_secret": secretsmanager.AddInstanceFields(secretsmanager.DataSourceIbmSmServiceCredentialsSecret()), "ibm_sm_en_registration": secretsmanager.AddInstanceFields(secretsmanager.DataSourceIbmSmEnRegistration()), // //Added for Satellite @@ -1246,6 +1248,7 @@ func Provider() *schema.Provider { "ibm_sm_public_certificate": secretsmanager.AddInstanceFields(secretsmanager.ResourceIbmSmPublicCertificate()), "ibm_sm_private_certificate": secretsmanager.AddInstanceFields(secretsmanager.ResourceIbmSmPrivateCertificate()), "ibm_sm_iam_credentials_secret": secretsmanager.AddInstanceFields(secretsmanager.ResourceIbmSmIamCredentialsSecret()), + "ibm_sm_service_credentials_secret": secretsmanager.AddInstanceFields(secretsmanager.ResourceIbmSmServiceCredentialsSecret()), "ibm_sm_username_password_secret": secretsmanager.AddInstanceFields(secretsmanager.ResourceIbmSmUsernamePasswordSecret()), "ibm_sm_kv_secret": secretsmanager.AddInstanceFields(secretsmanager.ResourceIbmSmKvSecret()), "ibm_sm_public_certificate_configuration_ca_lets_encrypt": secretsmanager.AddInstanceFields(secretsmanager.ResourceIbmSmPublicCertificateConfigurationCALetsEncrypt()), diff --git a/ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret.go b/ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret.go new file mode 100644 index 0000000000..bc5c17a8c9 --- /dev/null +++ b/ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret.go @@ -0,0 +1,506 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package secretsmanager + +import ( + "context" + "encoding/json" + "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/secrets-manager-go-sdk/v2/secretsmanagerv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIbmSmServiceCredentialsSecret() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIbmSmServiceCredentialsSecretRead, + + Schema: map[string]*schema.Schema{ + "secret_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ExactlyOneOf: []string{"secret_id", "name"}, + Description: "The ID of the secret.", + }, + "created_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier that is associated with the entity that created the secret.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date when a resource was created. The date format follows RFC 3339.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A CRN that uniquely identifies an IBM Cloud resource.", + }, + "custom_metadata": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "The secret metadata that a user can customize.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An extended description of your secret.To protect your privacy, do not use personal data, such as your name or location, as a description for your secret group.", + }, + "downloaded": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether the secret data that is associated with a secret version was retrieved in a call to the service API.", + }, + "labels": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Labels that you can use to search for secrets in your instance.Up to 30 labels can be created.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "locks_total": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The number of locks of the secret.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ExactlyOneOf: []string{"secret_id", "name"}, + RequiredWith: []string{"secret_group_name"}, + Description: "The human-readable name of your secret.", + }, + + "secret_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + ForceNew: true, + Description: "A v4 UUID identifier, or `default` secret group.", + }, + "secret_group_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + RequiredWith: []string{"name"}, + Description: "The human-readable name of your secret group.", + }, + "secret_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The secret type. Supported types are arbitrary, certificates (imported, public, and private), IAM credentials, key-value, and user credentials.", + }, + "state": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The secret state that is based on NIST SP 800-57. States are integers and correspond to the `Pre-activation = 0`, `Active = 1`, `Suspended = 2`, `Deactivated = 3`, and `Destroyed = 5` values.", + }, + "state_description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A text representation of the secret state.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date when a resource was recently modified. The date format follows RFC 3339.", + }, + "versions_total": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The number of versions of the secret.", + }, + "ttl": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The time-to-live (TTL) or lease duration to assign to generated credentials.", + }, + "rotation": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Determines whether Secrets Manager rotates your secrets automatically.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "auto_rotate": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Determines whether Secrets Manager rotates your secret automatically.Default is `false`. If `auto_rotate` is set to `true` the service rotates your secret based on the defined interval.", + }, + "interval": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The length of the secret rotation time interval.", + }, + "unit": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The units for the secret rotation time interval.", + }, + }, + }, + }, + "next_rotation_date": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date that the secret is scheduled for automatic rotation. The service automatically creates a new version of the secret on its next rotation date. This field exists only for secrets that have an existing rotation policy.", + }, + "credentials": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Sensitive: true, + Description: "The properties of the service credentials secret payload.", + }, + "source_service": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The properties required for creating the service credentials for the specified source service instance.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instance": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The source service instance identifier.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A CRN that uniquely identifies a service credentials target.", + }, + }, + }, + }, + "role": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The service-specific custom role object, CRN role is accepted. Refer to the service’s documentation for supported roles.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN role identifier for creating a service-id.", + }, + }, + }, + }, + "iam": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The source service IAM data is returned in case IAM credentials where created for this secret.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "apikey": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The IAM apikey metadata for the IAM credentials that were generated.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IAM API key name for the generated service credentials.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IAM API key description for the generated service credentials.", + }, + }, + }, + }, + "role": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The IAM role for the generate service credentials.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IAM role CRN assigned to the generated service credentials.", + }, + }, + }, + }, + "serviceid": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The IAM serviceid for the generated service credentials.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IAM Service ID CRN.", + }, + }, + }, + }, + }, + }, + }, + "resource_key": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The source service resource key data of the generated service credentials.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource key CRN of the generated service credentials.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource key name of the generated service credentials.", + }, + }, + }, + }, + "parameters": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "The collection of parameters for the service credentials target.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIbmSmServiceCredentialsSecretRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + ServiceCredentialsSecretIntf, region, instanceId, diagError := getSecretByIdOrByName(context, d, meta, ServiceCredentialsSecretType) + if diagError != nil { + return diagError + } + + ServiceCredentialsSecret := ServiceCredentialsSecretIntf.(*secretsmanagerv2.ServiceCredentialsSecret) + d.SetId(fmt.Sprintf("%s/%s/%s", region, instanceId, *ServiceCredentialsSecret.ID)) + + var err error + if err = d.Set("region", region); err != nil { + return diag.FromErr(fmt.Errorf("Error setting region: %s", err)) + } + if err = d.Set("created_by", ServiceCredentialsSecret.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + } + + if err = d.Set("created_at", DateTimeToRFC3339(ServiceCredentialsSecret.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + + if err = d.Set("crn", ServiceCredentialsSecret.Crn); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if ServiceCredentialsSecret.CustomMetadata != nil { + convertedMap := make(map[string]interface{}, len(ServiceCredentialsSecret.CustomMetadata)) + for k, v := range ServiceCredentialsSecret.CustomMetadata { + convertedMap[k] = v + } + + if err = d.Set("custom_metadata", flex.Flatten(convertedMap)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting custom_metadata: %s", err)) + } + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting custom_metadata %s", err)) + } + } + + if err = d.Set("description", ServiceCredentialsSecret.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + + if err = d.Set("downloaded", ServiceCredentialsSecret.Downloaded); err != nil { + return diag.FromErr(fmt.Errorf("Error setting downloaded: %s", err)) + } + + if ServiceCredentialsSecret.Labels != nil { + if err = d.Set("labels", ServiceCredentialsSecret.Labels); err != nil { + return diag.FromErr(fmt.Errorf("Error setting labels: %s", err)) + } + } + + if err = d.Set("locks_total", flex.IntValue(ServiceCredentialsSecret.LocksTotal)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting locks_total: %s", err)) + } + + if err = d.Set("name", ServiceCredentialsSecret.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("secret_group_id", ServiceCredentialsSecret.SecretGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting secret_group_id: %s", err)) + } + + if err = d.Set("secret_type", ServiceCredentialsSecret.SecretType); err != nil { + return diag.FromErr(fmt.Errorf("Error setting secret_type: %s", err)) + } + + if err = d.Set("state", flex.IntValue(ServiceCredentialsSecret.State)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + if err = d.Set("state_description", ServiceCredentialsSecret.StateDescription); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state_description: %s", err)) + } + + if err = d.Set("updated_at", DateTimeToRFC3339(ServiceCredentialsSecret.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + if err = d.Set("versions_total", flex.IntValue(ServiceCredentialsSecret.VersionsTotal)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting versions_total: %s", err)) + } + + if err = d.Set("ttl", ServiceCredentialsSecret.TTL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting ttl: %s", err)) + } + + rotation := []map[string]interface{}{} + if ServiceCredentialsSecret.Rotation != nil { + modelMap, err := dataSourceIbmSmServiceCredentialsSecretRotationPolicyToMap(ServiceCredentialsSecret.Rotation.(*secretsmanagerv2.RotationPolicy)) + if err != nil { + return diag.FromErr(err) + } + rotation = append(rotation, modelMap) + } + if err = d.Set("rotation", rotation); err != nil { + return diag.FromErr(fmt.Errorf("Error setting rotation %s", err)) + } + + if err = d.Set("next_rotation_date", DateTimeToRFC3339(ServiceCredentialsSecret.NextRotationDate)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting next_rotation_date: %s", err)) + } + + if ServiceCredentialsSecret.Credentials != nil { + var credInterface map[string]interface{} + cred, _ := json.Marshal(ServiceCredentialsSecret.Credentials) + json.Unmarshal(cred, &credInterface) + if err = d.Set("credentials", flex.Flatten(credInterface)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting credentials: %s", err)) + } + } + + sourceServiceMap, err := dataSourceIbmSmServiceCredentialsSecretSourceServiceToMap(ServiceCredentialsSecret.SourceService) + if err != nil { + return diag.FromErr(err) + } + if len(sourceServiceMap) > 0 { + if err = d.Set("source_service", []map[string]interface{}{sourceServiceMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting source_service: %s", err)) + } + } + + return nil +} + +func dataSourceIbmSmServiceCredentialsSecretRotationPolicyToMap(model *secretsmanagerv2.RotationPolicy) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.AutoRotate != nil { + modelMap["auto_rotate"] = *model.AutoRotate + } + if model.Interval != nil { + modelMap["interval"] = *model.Interval + } + if model.Unit != nil { + modelMap["unit"] = *model.Unit + } + return modelMap, nil +} + +func dataSourceIbmSmServiceCredentialsSecretSourceServiceToMap(sourceService *secretsmanagerv2.ServiceCredentialsSecretSourceService) (map[string]interface{}, error) { + mainModelMap := make(map[string]interface{}) + if sourceService.Instance != nil { + instanceMap := make(map[string]interface{}) + instanceModel := sourceService.Instance + if instanceModel.Crn != nil { + instanceMap["crn"] = instanceModel.Crn + } + mainModelMap["instance"] = []map[string]interface{}{instanceMap} + } + + if sourceService.Role != nil { + roleMap := make(map[string]interface{}) + roleModel := sourceService.Role + if roleModel.Crn != nil { + roleMap["crn"] = roleModel.Crn + } + mainModelMap["role"] = []map[string]interface{}{roleMap} + } + + if sourceService.Iam != nil { + iamMap := make(map[string]interface{}) + iamModel := sourceService.Iam + + // apikey + if iamModel.Apikey != nil { + iamApikeyMap := make(map[string]interface{}) + iamApikeyModel := iamModel.Apikey + if iamApikeyModel.Name != nil { + iamApikeyMap["name"] = iamApikeyModel.Name + } + if iamApikeyModel.Description != nil { + iamApikeyMap["description"] = iamApikeyModel.Description + } + iamMap["apikey"] = []map[string]interface{}{iamApikeyMap} + } + + // role + if iamModel.Role != nil { + iamRoleMap := make(map[string]interface{}) + iamRoleModel := iamModel.Role + if iamRoleModel.Crn != nil { + iamRoleMap["crn"] = iamRoleModel.Crn + } + iamMap["role"] = []map[string]interface{}{iamRoleMap} + } + + // service id + if iamModel.Serviceid != nil { + iamServiceidMap := make(map[string]interface{}) + iamServiceidModel := iamModel.Serviceid + if iamServiceidModel.Crn != nil { + iamServiceidMap["crn"] = iamServiceidModel.Crn + } + iamMap["serviceid"] = []map[string]interface{}{iamServiceidMap} + } + + mainModelMap["iam"] = []map[string]interface{}{iamMap} + + } + + if sourceService.ResourceKey != nil { + resourceKeyMap := make(map[string]interface{}) + resourceKeyModel := sourceService.ResourceKey + if resourceKeyModel.Crn != nil { + resourceKeyMap["crn"] = resourceKeyModel.Crn + } + if resourceKeyModel.Name != nil { + resourceKeyMap["name"] = resourceKeyModel.Name + } + mainModelMap["resource_key"] = []map[string]interface{}{resourceKeyMap} + } + + if sourceService.Parameters != nil { + parametersMap := sourceService.Parameters.GetProperties() + for k, v := range parametersMap { + parametersMap[k] = fmt.Sprint(v) + } + if sourceService.Parameters.ServiceidCrn != nil { + if len(parametersMap) == 0 { + parametersMap = make(map[string]interface{}) + } + parametersMap["serviceid_crn"] = sourceService.Parameters.ServiceidCrn + } + mainModelMap["parameters"] = parametersMap + } + + return mainModelMap, nil +} diff --git a/ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret_metadata.go b/ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret_metadata.go new file mode 100644 index 0000000000..141e0f9e6d --- /dev/null +++ b/ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret_metadata.go @@ -0,0 +1,494 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package secretsmanager + +import ( + "context" + "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/secrets-manager-go-sdk/v2/secretsmanagerv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "log" +) + +func DataSourceIbmSmServiceCredentialsSecretMetadata() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIbmSmServiceCredentialsSecretMetadataRead, + + Schema: map[string]*schema.Schema{ + "secret_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The ID of the secret.", + }, + "created_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier that is associated with the entity that created the secret.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date when a resource was created. The date format follows RFC 3339.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A CRN that uniquely identifies an IBM Cloud resource.", + }, + "custom_metadata": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "The secret metadata that a user can customize.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An extended description of your secret.To protect your privacy, do not use personal data, such as your name or location, as a description for your secret group.", + }, + "downloaded": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether the secret data that is associated with a secret version was retrieved in a call to the service API.", + }, + "labels": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Labels that you can use to search for secrets in your instance.Up to 30 labels can be created.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "locks_total": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The number of locks of the secret.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The human-readable name of your secret.", + }, + "secret_group_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + ForceNew: true, + Description: "A v4 UUID identifier, or `default` secret group.", + }, + "secret_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The secret type. Supported types are arbitrary, certificates (imported, public, and private), IAM credentials, key-value, and user credentials.", + }, + "state": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The secret state that is based on NIST SP 800-57. States are integers and correspond to the `Pre-activation = 0`, `Active = 1`, `Suspended = 2`, `Deactivated = 3`, and `Destroyed = 5` values.", + }, + "state_description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A text representation of the secret state.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date when a resource was recently modified. The date format follows RFC 3339.", + }, + "versions_total": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The number of versions of the secret.", + }, + "ttl": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The time-to-live (TTL) or lease duration to assign to generated credentials.", + }, + "rotation": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Determines whether Secrets Manager rotates your secrets automatically.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "auto_rotate": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Determines whether Secrets Manager rotates your secret automatically.Default is `false`. If `auto_rotate` is set to `true` the service rotates your secret based on the defined interval.", + }, + "interval": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The length of the secret rotation time interval.", + }, + "unit": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The units for the secret rotation time interval.", + }, + }, + }, + }, + "next_rotation_date": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date that the secret is scheduled for automatic rotation. The service automatically creates a new version of the secret on its next rotation date. This field exists only for secrets that have an existing rotation policy.", + }, + "source_service": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The properties required for creating the service credentials for the specified source service instance.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instance": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The source service instance identifier.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A CRN that uniquely identifies a service credentials target.", + }, + }, + }, + }, + "role": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The service-specific custom role object, CRN role is accepted. Refer to the service’s documentation for supported roles.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN role identifier for creating a service-id.", + }, + }, + }, + }, + "iam": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The source service IAM data is returned in case IAM credentials where created for this secret.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "apikey": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The IAM apikey metadata for the IAM credentials that were generated.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IAM API key name for the generated service credentials.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IAM API key description for the generated service credentials.", + }, + }, + }, + }, + "role": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The IAM role for the generate service credentials.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IAM role CRN assigned to the generated service credentials.", + }, + }, + }, + }, + "serviceid": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The IAM serviceid for the generated service credentials.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IAM Service ID CRN.", + }, + }, + }, + }, + }, + }, + }, + "resource_key": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The source service resource key data of the generated service credentials.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource key CRN of the generated service credentials.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource key name of the generated service credentials.", + }, + }, + }, + }, + "parameters": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Description: "The collection of parameters for the service credentials target.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIbmSmServiceCredentialsSecretMetadataRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + secretsManagerClient, err := meta.(conns.ClientSession).SecretsManagerV2() + if err != nil { + return diag.FromErr(err) + } + + region := getRegion(secretsManagerClient, d) + instanceId := d.Get("instance_id").(string) + secretsManagerClient = getClientWithInstanceEndpoint(secretsManagerClient, instanceId, region, getEndpointType(secretsManagerClient, d)) + + getSecretMetadataOptions := &secretsmanagerv2.GetSecretMetadataOptions{} + + secretId := d.Get("secret_id").(string) + getSecretMetadataOptions.SetID(secretId) + + ServiceCredentialsSecretMetadataIntf, response, err := secretsManagerClient.GetSecretMetadataWithContext(context, getSecretMetadataOptions) + if err != nil { + log.Printf("[DEBUG] GetSecretMetadataWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetSecretMetadataWithContext failed %s\n%s", err, response)) + } + ServiceCredentialsSecretMetadata := ServiceCredentialsSecretMetadataIntf.(*secretsmanagerv2.ServiceCredentialsSecretMetadata) + + d.SetId(fmt.Sprintf("%s/%s/%s", region, instanceId, secretId)) + + if err = d.Set("region", region); err != nil { + return diag.FromErr(fmt.Errorf("Error setting region: %s", err)) + } + if err = d.Set("created_by", ServiceCredentialsSecretMetadata.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + } + + if err = d.Set("created_at", DateTimeToRFC3339(ServiceCredentialsSecretMetadata.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + + if err = d.Set("crn", ServiceCredentialsSecretMetadata.Crn); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if ServiceCredentialsSecretMetadata.CustomMetadata != nil { + convertedMap := make(map[string]interface{}, len(ServiceCredentialsSecretMetadata.CustomMetadata)) + for k, v := range ServiceCredentialsSecretMetadata.CustomMetadata { + convertedMap[k] = v + } + + if err = d.Set("custom_metadata", flex.Flatten(convertedMap)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting custom_metadata: %s", err)) + } + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting custom_metadata %s", err)) + } + } + + if err = d.Set("description", ServiceCredentialsSecretMetadata.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + + if err = d.Set("downloaded", ServiceCredentialsSecretMetadata.Downloaded); err != nil { + return diag.FromErr(fmt.Errorf("Error setting downloaded: %s", err)) + } + + if ServiceCredentialsSecretMetadata.Labels != nil { + if err = d.Set("labels", ServiceCredentialsSecretMetadata.Labels); err != nil { + return diag.FromErr(fmt.Errorf("Error setting labels: %s", err)) + } + } + + if err = d.Set("locks_total", flex.IntValue(ServiceCredentialsSecretMetadata.LocksTotal)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting locks_total: %s", err)) + } + + if err = d.Set("name", ServiceCredentialsSecretMetadata.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + if err = d.Set("secret_group_id", ServiceCredentialsSecretMetadata.SecretGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting secret_group_id: %s", err)) + } + + if err = d.Set("secret_type", ServiceCredentialsSecretMetadata.SecretType); err != nil { + return diag.FromErr(fmt.Errorf("Error setting secret_type: %s", err)) + } + + if err = d.Set("state", flex.IntValue(ServiceCredentialsSecretMetadata.State)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + + if err = d.Set("state_description", ServiceCredentialsSecretMetadata.StateDescription); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state_description: %s", err)) + } + + if err = d.Set("updated_at", DateTimeToRFC3339(ServiceCredentialsSecretMetadata.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + + if err = d.Set("versions_total", flex.IntValue(ServiceCredentialsSecretMetadata.VersionsTotal)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting versions_total: %s", err)) + } + + if err = d.Set("ttl", ServiceCredentialsSecretMetadata.TTL); err != nil { + return diag.FromErr(fmt.Errorf("Error setting ttl: %s", err)) + } + + rotation := []map[string]interface{}{} + if ServiceCredentialsSecretMetadata.Rotation != nil { + modelMap, err := dataSourceIbmSmServiceCredentialsSecretMetadataRotationPolicyToMap(ServiceCredentialsSecretMetadata.Rotation.(*secretsmanagerv2.RotationPolicy)) + if err != nil { + return diag.FromErr(err) + } + rotation = append(rotation, modelMap) + } + if err = d.Set("rotation", rotation); err != nil { + return diag.FromErr(fmt.Errorf("Error setting rotation %s", err)) + } + + if err = d.Set("next_rotation_date", DateTimeToRFC3339(ServiceCredentialsSecretMetadata.NextRotationDate)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting next_rotation_date: %s", err)) + } + + sourceServiceMap, err := dataSourceIbmSmServiceCredentialsSecretMetadataSourceServiceToMap(ServiceCredentialsSecretMetadata.SourceService) + if err != nil { + return diag.FromErr(err) + } + if len(sourceServiceMap) > 0 { + if err = d.Set("source_service", []map[string]interface{}{sourceServiceMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting source_service: %s", err)) + } + } + + return nil +} + +func dataSourceIbmSmServiceCredentialsSecretMetadataRotationPolicyToMap(model *secretsmanagerv2.RotationPolicy) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.AutoRotate != nil { + modelMap["auto_rotate"] = *model.AutoRotate + } + if model.Interval != nil { + modelMap["interval"] = *model.Interval + } + if model.Unit != nil { + modelMap["unit"] = *model.Unit + } + return modelMap, nil +} + +func dataSourceIbmSmServiceCredentialsSecretMetadataSourceServiceToMap(sourceService *secretsmanagerv2.ServiceCredentialsSecretSourceService) (map[string]interface{}, error) { + mainModelMap := make(map[string]interface{}) + if sourceService.Instance != nil { + instanceMap := make(map[string]interface{}) + instanceModel := sourceService.Instance + if instanceModel.Crn != nil { + instanceMap["crn"] = instanceModel.Crn + } + mainModelMap["instance"] = []map[string]interface{}{instanceMap} + } + + if sourceService.Role != nil { + roleMap := make(map[string]interface{}) + roleModel := sourceService.Role + if roleModel.Crn != nil { + roleMap["crn"] = roleModel.Crn + } + mainModelMap["role"] = []map[string]interface{}{roleMap} + } + + if sourceService.Iam != nil { + iamMap := make(map[string]interface{}) + iamModel := sourceService.Iam + + // apikey + if iamModel.Apikey != nil { + iamApikeyMap := make(map[string]interface{}) + iamApikeyModel := iamModel.Apikey + if iamApikeyModel.Name != nil { + iamApikeyMap["name"] = iamApikeyModel.Name + } + if iamApikeyModel.Description != nil { + iamApikeyMap["description"] = iamApikeyModel.Description + } + iamMap["apikey"] = []map[string]interface{}{iamApikeyMap} + } + + // role + if iamModel.Role != nil { + iamRoleMap := make(map[string]interface{}) + iamRoleModel := iamModel.Role + if iamRoleModel.Crn != nil { + iamRoleMap["crn"] = iamRoleModel.Crn + } + iamMap["role"] = []map[string]interface{}{iamRoleMap} + } + + // service id + if iamModel.Serviceid != nil { + iamServiceidMap := make(map[string]interface{}) + iamServiceidModel := iamModel.Serviceid + if iamServiceidModel.Crn != nil { + iamServiceidMap["crn"] = iamServiceidModel.Crn + } + iamMap["serviceid"] = []map[string]interface{}{iamServiceidMap} + } + + mainModelMap["iam"] = []map[string]interface{}{iamMap} + + } + + if sourceService.ResourceKey != nil { + resourceKeyMap := make(map[string]interface{}) + resourceKeyModel := sourceService.ResourceKey + if resourceKeyModel.Crn != nil { + resourceKeyMap["crn"] = resourceKeyModel.Crn + } + if resourceKeyModel.Name != nil { + resourceKeyMap["name"] = resourceKeyModel.Name + } + mainModelMap["resource_key"] = []map[string]interface{}{resourceKeyMap} + } + + if sourceService.Parameters != nil { + parametersMap := sourceService.Parameters.GetProperties() + for k, v := range parametersMap { + parametersMap[k] = fmt.Sprint(v) + } + if sourceService.Parameters.ServiceidCrn != nil { + if len(parametersMap) == 0 { + parametersMap = make(map[string]interface{}) + } + parametersMap["serviceid_crn"] = sourceService.Parameters.ServiceidCrn + } + mainModelMap["parameters"] = parametersMap + } + + return mainModelMap, nil +} diff --git a/ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret_metadata_test.go b/ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret_metadata_test.go new file mode 100644 index 0000000000..91ad1c0491 --- /dev/null +++ b/ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret_metadata_test.go @@ -0,0 +1,74 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package secretsmanager_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIbmSmServiceCredentialsSecretMetadataDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIbmSmServiceCredentialsSecretMetadataDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret_metadata.sm_service_credentials_secret_metadata", "secret_id"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret_metadata.sm_service_credentials_secret_metadata", "instance_id"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret_metadata.sm_service_credentials_secret_metadata", "created_by"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret_metadata.sm_service_credentials_secret_metadata", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret_metadata.sm_service_credentials_secret_metadata", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret_metadata.sm_service_credentials_secret_metadata", "secret_group_id"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret_metadata.sm_service_credentials_secret_metadata", "secret_type"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret_metadata.sm_service_credentials_secret_metadata", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret_metadata.sm_service_credentials_secret_metadata", "versions_total"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret_metadata.sm_service_credentials_secret_metadata", "rotation.#"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret_metadata.sm_service_credentials_secret_metadata", "ttl"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret_metadata.sm_service_credentials_secret_metadata", "source_service.#"), + ), + }, + }, + }) +} + +func testAccCheckIbmSmServiceCredentialsSecretMetadataDataSourceConfigBasic() string { + return fmt.Sprintf(` + resource "ibm_sm_service_credentials_secret" "sm_service_credentials_secret_instance" { + instance_id = "%s" + region = "%s" + custom_metadata = {"key":"value"} + description = "Extended description for this secret." + labels = ["my-label"] + rotation { + auto_rotate = true + interval = 1 + unit = "day" + } + secret_group_id = "default" + name = "service_credentials-datasource-terraform-test" + ttl = "%s" + source_service { + instance { + crn = "%s" + } + parameters = %s + role { + crn = "%s" + } + } + } + + data "ibm_sm_service_credentials_secret_metadata" "sm_service_credentials_secret_metadata" { + instance_id = "%s" + region = "%s" + secret_id = ibm_sm_service_credentials_secret.sm_service_credentials_secret_instance.secret_id + } + `, acc.SecretsManagerInstanceID, acc.SecretsManagerInstanceRegion, serviceCredentialsTtl, acc.SecretsManagerServiceCredentialsCosCrn, serviceCredentialsParameters, serviceCredentialsRoleCrn, acc.SecretsManagerInstanceID, acc.SecretsManagerInstanceRegion) +} diff --git a/ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret_test.go b/ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret_test.go new file mode 100644 index 0000000000..eadf2f92c8 --- /dev/null +++ b/ibm/service/secretsmanager/data_source_ibm_sm_service_credentials_secret_test.go @@ -0,0 +1,83 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package secretsmanager_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIbmSmServiceCredentialsSecretDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIbmSmServiceCredentialsSecretDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret.sm_service_credentials_secret", "secret_id"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret.sm_service_credentials_secret", "instance_id"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret.sm_service_credentials_secret", "created_by"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret.sm_service_credentials_secret", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret.sm_service_credentials_secret", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret.sm_service_credentials_secret", "secret_group_id"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret.sm_service_credentials_secret", "secret_type"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret.sm_service_credentials_secret", "updated_at"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret.sm_service_credentials_secret", "versions_total"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret.sm_service_credentials_secret", "rotation.#"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret.sm_service_credentials_secret", "ttl"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret.sm_service_credentials_secret", "source_service.#"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret.sm_service_credentials_secret_by_name", "name"), + resource.TestCheckResourceAttrSet("data.ibm_sm_service_credentials_secret.sm_service_credentials_secret_by_name", "secret_group_name"), + ), + }, + }, + }) +} + +func testAccCheckIbmSmServiceCredentialsSecretDataSourceConfigBasic() string { + return fmt.Sprintf(` + resource "ibm_sm_service_credentials_secret" "sm_service_credentials_secret_instance" { + instance_id = "%s" + region = "%s" + custom_metadata = {"key":"value"} + description = "Extended description for this secret." + labels = ["my-label"] + rotation { + auto_rotate = true + interval = 1 + unit = "day" + } + secret_group_id = "default" + name = "service_credentials-datasource-terraform-test" + ttl = "%s" + source_service { + instance { + crn = "%s" + } + parameters = %s + role { + crn = "%s" + } + } + } + + data "ibm_sm_service_credentials_secret" "sm_service_credentials_secret" { + instance_id = "%s" + region = "%s" + secret_id = ibm_sm_service_credentials_secret.sm_service_credentials_secret_instance.secret_id + } + + data "ibm_sm_service_credentials_secret" "sm_service_credentials_secret_by_name" { + instance_id = "%s" + region = "%s" + name = ibm_sm_service_credentials_secret.sm_service_credentials_secret_instance.name + secret_group_name = "default" + } + `, acc.SecretsManagerInstanceID, acc.SecretsManagerInstanceRegion, serviceCredentialsTtl, acc.SecretsManagerServiceCredentialsCosCrn, serviceCredentialsParameters, serviceCredentialsRoleCrn, acc.SecretsManagerInstanceID, acc.SecretsManagerInstanceRegion, acc.SecretsManagerInstanceID, acc.SecretsManagerInstanceRegion) +} diff --git a/ibm/service/secretsmanager/resource_ibm_sm_service_credentilas_secret.go b/ibm/service/secretsmanager/resource_ibm_sm_service_credentilas_secret.go new file mode 100644 index 0000000000..7d5e211b0d --- /dev/null +++ b/ibm/service/secretsmanager/resource_ibm_sm_service_credentilas_secret.go @@ -0,0 +1,790 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 +// . +package secretsmanager + +import ( + "context" + "encoding/json" + "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/secrets-manager-go-sdk/v2/secretsmanagerv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "log" + "strconv" + "strings" +) + +func ResourceIbmSmServiceCredentialsSecret() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIbmSmServiceCredentialsSecretCreate, + ReadContext: resourceIbmSmServiceCredentialsSecretRead, + UpdateContext: resourceIbmSmServiceCredentialsSecretUpdate, + DeleteContext: resourceIbmSmServiceCredentialsSecretDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "secret_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The secret type. Supported types are arbitrary, certificates (imported, public, and private), IAM credentials, key-value, and user credentials.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "A human-readable name to assign to your secret.To protect your privacy, do not use personal data, such as your name or location, as a name for your secret.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "An extended description of your secret.To protect your privacy, do not use personal data, such as your name or location, as a description for your secret group.", + }, + "secret_group_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Description: "A v4 UUID identifier, or `default` secret group.", + }, + "labels": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "Labels that you can use to search for secrets in your instance.Up to 30 labels can be created.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "custom_metadata": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Computed: true, + Description: "The secret metadata that a user can customize.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "version_custom_metadata": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + Computed: true, + Description: "The secret version metadata that a user can customize.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "created_by": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier that is associated with the entity that created the secret.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date when a resource was created. The date format follows RFC 3339.", + }, + "credentials": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + Sensitive: true, + Description: "The properties of the service credentials secret payload.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A CRN that uniquely identifies an IBM Cloud resource.", + }, + "downloaded": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether the secret data that is associated with a secret version was retrieved in a call to the service API.", + }, + "locks_total": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The number of locks of the secret.", + }, + "next_rotation_date": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date that the secret is scheduled for automatic rotation. The service automatically creates a new version of the secret on its next rotation date. This field exists only for secrets that have an existing rotation policy.", + }, + "rotation": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "Determines whether Secrets Manager rotates your secrets automatically.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "auto_rotate": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Determines whether Secrets Manager rotates your secret automatically.Default is `false`. If `auto_rotate` is set to `true` the service rotates your secret based on the defined interval.", + }, + "interval": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Computed: true, + Description: "The length of the secret rotation time interval.", + DiffSuppressFunc: rotationAttributesDiffSuppress, + }, + "unit": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The units for the secret rotation time interval.", + DiffSuppressFunc: rotationAttributesDiffSuppress, + }, + }, + }, + }, + "source_service": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Required: true, + ForceNew: true, + Description: "The properties required for creating the service credentials for the specified source service instance.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instance": &schema.Schema{ + Type: schema.TypeList, + Required: true, + MaxItems: 1, + ForceNew: true, + Description: "The source service instance identifier.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "A CRN that uniquely identifies a service credentials target.", + }, + }, + }, + }, + "role": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Computed: true, + ForceNew: true, + MaxItems: 1, + Description: "The service-specific custom role object, CRN role is accepted. Refer to the service’s documentation for supported roles.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Description: "The CRN role identifier for creating a service-id.", + }, + }, + }, + }, + "iam": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The source service IAM data is returned in case IAM credentials where created for this secret.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "apikey": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The IAM apikey metadata for the IAM credentials that were generated.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IAM API key name for the generated service credentials.", + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IAM API key description for the generated service credentials.", + }, + }, + }, + }, + "role": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The IAM role for the generate service credentials.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IAM role CRN assigned to the generated service credentials.", + }, + }, + }, + }, + "serviceid": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The IAM serviceid for the generated service credentials.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IAM Service ID CRN.", + }, + }, + }, + }, + }, + }, + }, + "resource_key": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The source service resource key data of the generated service credentials.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource key CRN of the generated service credentials.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource key name of the generated service credentials.", + }, + }, + }, + }, + "parameters": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + ForceNew: true, + Description: "The collection of parameters for the service credentials target.", + }, + }, + }, + }, + "state": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The secret state that is based on NIST SP 800-57. States are integers and correspond to the `Pre-activation = 0`, `Active = 1`, `Suspended = 2`, `Deactivated = 3`, and `Destroyed = 5` values.", + }, + "state_description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A text representation of the secret state.", + }, + "ttl": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The time-to-live (TTL) or lease duration to assign to generated credentials.", + }, + "updated_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date when a resource was recently modified. The date format follows RFC 3339.", + }, + "versions_total": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The number of versions of the secret.", + }, + "secret_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A v4 UUID identifier.", + }, + }, + } +} + +func resourceIbmSmServiceCredentialsSecretCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + secretsManagerClient, err := meta.(conns.ClientSession).SecretsManagerV2() + if err != nil { + return diag.FromErr(err) + } + + region := getRegion(secretsManagerClient, d) + instanceId := d.Get("instance_id").(string) + secretsManagerClient = getClientWithInstanceEndpoint(secretsManagerClient, instanceId, region, getEndpointType(secretsManagerClient, d)) + + createSecretOptions := &secretsmanagerv2.CreateSecretOptions{} + + secretPrototypeModel, err := resourceIbmSmServiceCredentialsSecretMapToSecretPrototype(d) + if err != nil { + return diag.FromErr(err) + } + createSecretOptions.SetSecretPrototype(secretPrototypeModel) + + secretIntf, response, err := secretsManagerClient.CreateSecretWithContext(context, createSecretOptions) + if err != nil { + log.Printf("[DEBUG] CreateSecretWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateSecretWithContext failed %s\n%s", err, response)) + } + + secret := secretIntf.(*secretsmanagerv2.ServiceCredentialsSecret) + d.SetId(fmt.Sprintf("%s/%s/%s", region, instanceId, *secret.ID)) + d.Set("secret_id", *secret.ID) + + return resourceIbmSmServiceCredentialsSecretRead(context, d, meta) +} + +func resourceIbmSmServiceCredentialsSecretRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + secretsManagerClient, err := meta.(conns.ClientSession).SecretsManagerV2() + if err != nil { + return diag.FromErr(err) + } + + id := strings.Split(d.Id(), "/") + if len(id) != 3 { + return diag.Errorf("Wrong format of resource ID. To import a secret use the format `//`") + } + region := id[0] + instanceId := id[1] + secretId := id[2] + secretsManagerClient = getClientWithInstanceEndpoint(secretsManagerClient, instanceId, region, getEndpointType(secretsManagerClient, d)) + + getSecretOptions := &secretsmanagerv2.GetSecretOptions{} + + getSecretOptions.SetID(secretId) + + secretIntf, response, err := secretsManagerClient.GetSecretWithContext(context, getSecretOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetSecretWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetSecretWithContext failed %s\n%s", err, response)) + } + + secret := secretIntf.(*secretsmanagerv2.ServiceCredentialsSecret) + + if err = d.Set("secret_id", secretId); err != nil { + return diag.FromErr(fmt.Errorf("Error setting secret_id: %s", err)) + } + if err = d.Set("instance_id", instanceId); err != nil { + return diag.FromErr(fmt.Errorf("Error setting instance_id: %s", err)) + } + if err = d.Set("region", region); err != nil { + return diag.FromErr(fmt.Errorf("Error setting region: %s", err)) + } + if err = d.Set("created_by", secret.CreatedBy); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_by: %s", err)) + } + if err = d.Set("created_at", DateTimeToRFC3339(secret.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + if err = d.Set("crn", secret.Crn); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("downloaded", secret.Downloaded); err != nil { + return diag.FromErr(fmt.Errorf("Error setting downloaded: %s", err)) + } + if err = d.Set("locks_total", flex.IntValue(secret.LocksTotal)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting locks_total: %s", err)) + } + if err = d.Set("name", secret.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + if err = d.Set("secret_group_id", secret.SecretGroupID); err != nil { + return diag.FromErr(fmt.Errorf("Error setting secret_group_id: %s", err)) + } + if err = d.Set("secret_type", secret.SecretType); err != nil { + return diag.FromErr(fmt.Errorf("Error setting secret_type: %s", err)) + } + if err = d.Set("state", flex.IntValue(secret.State)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state: %s", err)) + } + if err = d.Set("state_description", secret.StateDescription); err != nil { + return diag.FromErr(fmt.Errorf("Error setting state_description: %s", err)) + } + if err = d.Set("updated_at", DateTimeToRFC3339(secret.UpdatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting updated_at: %s", err)) + } + if err = d.Set("versions_total", flex.IntValue(secret.VersionsTotal)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting versions_total: %s", err)) + } + if secret.CustomMetadata != nil { + d.Set("custom_metadata", secret.CustomMetadata) + } + if err = d.Set("description", secret.Description); err != nil { + return diag.FromErr(fmt.Errorf("Error setting description: %s", err)) + } + if secret.Labels != nil { + if err = d.Set("labels", secret.Labels); err != nil { + return diag.FromErr(fmt.Errorf("Error setting labels: %s", err)) + } + } + rotationMap, err := resourceIbmSmServiceCredentialsSecretRotationPolicyToMap(secret.Rotation) + if err != nil { + return diag.FromErr(err) + } + if len(rotationMap) > 0 { + if err = d.Set("rotation", []map[string]interface{}{rotationMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting rotation: %s", err)) + } + } + sourceServiceMap, err := resourceIbmSmServiceCredentialsSecretSourceServiceToMap(secret.SourceService) + if err != nil { + return diag.FromErr(err) + } + if len(sourceServiceMap) > 0 { + if err = d.Set("source_service", []map[string]interface{}{sourceServiceMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting source_service: %s", err)) + } + } + if secret.Credentials != nil { + var credInterface map[string]interface{} + cred, _ := json.Marshal(secret.Credentials) + json.Unmarshal(cred, &credInterface) + if err = d.Set("credentials", flex.Flatten(credInterface)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting credentials: %s", err)) + } + } + if err = d.Set("next_rotation_date", DateTimeToRFC3339(secret.NextRotationDate)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting next_rotation_date: %s", err)) + } + + // Call get version metadata API to get the current version_custom_metadata + getVersionMetdataOptions := &secretsmanagerv2.GetSecretVersionMetadataOptions{} + getVersionMetdataOptions.SetSecretID(secretId) + getVersionMetdataOptions.SetID("current") + + versionMetadataIntf, response, err := secretsManagerClient.GetSecretVersionMetadataWithContext(context, getVersionMetdataOptions) + if err != nil { + log.Printf("[DEBUG] GetSecretVersionMetadataWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetSecretVersionMetadataWithContext failed %s\n%s", err, response)) + } + + versionMetadata := versionMetadataIntf.(*secretsmanagerv2.ServiceCredentialsSecretVersionMetadata) + if versionMetadata.VersionCustomMetadata != nil { + if err = d.Set("version_custom_metadata", versionMetadata.VersionCustomMetadata); err != nil { + return diag.FromErr(fmt.Errorf("Error setting version_custom_metadata: %s", err)) + } + } + + return nil +} + +func resourceIbmSmServiceCredentialsSecretUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + secretsManagerClient, err := meta.(conns.ClientSession).SecretsManagerV2() + if err != nil { + return diag.FromErr(err) + } + + id := strings.Split(d.Id(), "/") + region := id[0] + instanceId := id[1] + secretId := id[2] + secretsManagerClient = getClientWithInstanceEndpoint(secretsManagerClient, instanceId, region, getEndpointType(secretsManagerClient, d)) + + updateSecretMetadataOptions := &secretsmanagerv2.UpdateSecretMetadataOptions{} + + updateSecretMetadataOptions.SetID(secretId) + + hasChange := false + + patchVals := &secretsmanagerv2.SecretMetadataPatch{} + + if d.HasChange("name") { + patchVals.Name = core.StringPtr(d.Get("name").(string)) + hasChange = true + } + if d.HasChange("description") { + patchVals.Description = core.StringPtr(d.Get("description").(string)) + hasChange = true + } + if d.HasChange("ttl") { + patchVals.TTL = core.StringPtr(d.Get("ttl").(string)) + hasChange = true + } + if d.HasChange("labels") { + labels := d.Get("labels").([]interface{}) + labelsParsed := make([]string, len(labels)) + for i, v := range labels { + labelsParsed[i] = fmt.Sprint(v) + } + patchVals.Labels = labelsParsed + hasChange = true + } + if d.HasChange("custom_metadata") { + patchVals.CustomMetadata = d.Get("custom_metadata").(map[string]interface{}) + hasChange = true + } + if d.HasChange("rotation") { + RotationModel, err := resourceIbmSmServiceCredentialsSecretMapToRotationPolicy(d.Get("rotation").([]interface{})[0].(map[string]interface{})) + if err != nil { + log.Printf("[DEBUG] UpdateSecretMetadataWithContext failed: Reading Rotation parameter failed: %s", err) + return diag.FromErr(fmt.Errorf("UpdateSecretMetadataWithContext failed: Reading Rotation parameter failed: %s", err)) + } + patchVals.Rotation = RotationModel + hasChange = true + } + + // Apply change in metadata (if changed) + if hasChange { + updateSecretMetadataOptions.SecretMetadataPatch, _ = patchVals.AsPatch() + _, response, err := secretsManagerClient.UpdateSecretMetadataWithContext(context, updateSecretMetadataOptions) + if err != nil { + log.Printf("[DEBUG] UpdateSecretMetadataWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateSecretMetadataWithContext failed %s\n%s", err, response)) + } + } + + if d.HasChange("version_custom_metadata") { + // Apply change to version_custom_metadata in current version + secretVersionMetadataPatchModel := new(secretsmanagerv2.SecretVersionMetadataPatch) + secretVersionMetadataPatchModel.VersionCustomMetadata = d.Get("version_custom_metadata").(map[string]interface{}) + secretVersionMetadataPatchModelAsPatch, _ := secretVersionMetadataPatchModel.AsPatch() + + updateSecretVersionOptions := &secretsmanagerv2.UpdateSecretVersionMetadataOptions{} + updateSecretVersionOptions.SetSecretID(secretId) + updateSecretVersionOptions.SetID("current") + updateSecretVersionOptions.SetSecretVersionMetadataPatch(secretVersionMetadataPatchModelAsPatch) + _, response, err := secretsManagerClient.UpdateSecretVersionMetadataWithContext(context, updateSecretVersionOptions) + if err != nil { + if hasChange { + // Call the read function to update the Terraform state with the change already applied to the metadata + resourceIbmSmServiceCredentialsSecretRead(context, d, meta) + } + log.Printf("[DEBUG] UpdateSecretVersionMetadataWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateSecretVersionMetadataWithContext failed %s\n%s", err, response)) + } + } + + return resourceIbmSmServiceCredentialsSecretRead(context, d, meta) +} + +func resourceIbmSmServiceCredentialsSecretDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + secretsManagerClient, err := meta.(conns.ClientSession).SecretsManagerV2() + if err != nil { + return diag.FromErr(err) + } + + id := strings.Split(d.Id(), "/") + region := id[0] + instanceId := id[1] + secretId := id[2] + secretsManagerClient = getClientWithInstanceEndpoint(secretsManagerClient, instanceId, region, getEndpointType(secretsManagerClient, d)) + + deleteSecretOptions := &secretsmanagerv2.DeleteSecretOptions{} + + deleteSecretOptions.SetID(secretId) + + response, err := secretsManagerClient.DeleteSecretWithContext(context, deleteSecretOptions) + if err != nil { + log.Printf("[DEBUG] DeleteSecretWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteSecretWithContext failed %s\n%s", err, response)) + } + + d.SetId("") + + return nil +} + +func resourceIbmSmServiceCredentialsSecretMapToSecretPrototype(d *schema.ResourceData) (*secretsmanagerv2.ServiceCredentialsSecretPrototype, error) { + model := &secretsmanagerv2.ServiceCredentialsSecretPrototype{} + model.SecretType = core.StringPtr("service_credentials") + + if _, ok := d.GetOk("name"); ok { + model.Name = core.StringPtr(d.Get("name").(string)) + } + if _, ok := d.GetOk("description"); ok { + model.Description = core.StringPtr(d.Get("description").(string)) + } + if _, ok := d.GetOk("secret_group_id"); ok { + model.SecretGroupID = core.StringPtr(d.Get("secret_group_id").(string)) + } + if _, ok := d.GetOk("labels"); ok { + labels := d.Get("labels").([]interface{}) + labelsParsed := make([]string, len(labels)) + for i, v := range labels { + labelsParsed[i] = fmt.Sprint(v) + } + model.Labels = labelsParsed + } + if _, ok := d.GetOk("ttl"); ok { + model.TTL = core.StringPtr(d.Get("ttl").(string)) + } + if _, ok := d.GetOk("rotation"); ok { + RotationModel, err := resourceIbmSmServiceCredentialsSecretMapToRotationPolicy(d.Get("rotation").([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Rotation = RotationModel + } + if _, ok := d.GetOk("source_service"); ok { + SourceServiceModel, err := resourceIbmSmServiceCredentialsSecretMapToSourceService(d.Get("source_service").([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.SourceService = SourceServiceModel + } + if _, ok := d.GetOk("custom_metadata"); ok { + model.CustomMetadata = d.Get("custom_metadata").(map[string]interface{}) + } + if _, ok := d.GetOk("version_custom_metadata"); ok { + model.VersionCustomMetadata = d.Get("version_custom_metadata").(map[string]interface{}) + } + return model, nil +} + +func resourceIbmSmServiceCredentialsSecretMapToRotationPolicy(modelMap map[string]interface{}) (secretsmanagerv2.RotationPolicyIntf, error) { + model := &secretsmanagerv2.RotationPolicy{} + if modelMap["auto_rotate"] != nil { + model.AutoRotate = core.BoolPtr(modelMap["auto_rotate"].(bool)) + } + if modelMap["interval"].(int) == 0 { + model.Interval = nil + } else { + model.Interval = core.Int64Ptr(int64(modelMap["interval"].(int))) + } + if modelMap["unit"] != nil && modelMap["unit"].(string) != "" { + model.Unit = core.StringPtr(modelMap["unit"].(string)) + } + return model, nil +} + +func resourceIbmSmServiceCredentialsSecretMapToSourceService(modelMap map[string]interface{}) (*secretsmanagerv2.ServiceCredentialsSecretSourceService, error) { + mainModel := &secretsmanagerv2.ServiceCredentialsSecretSourceService{} + + if modelMap["instance"] != nil && len(modelMap["instance"].([]interface{})) > 0 { + instanceModel := &secretsmanagerv2.ServiceCredentialsSourceServiceInstance{} + if modelMap["instance"].([]interface{})[0].(map[string]interface{})["crn"].(string) != "" { + instanceModel.Crn = core.StringPtr(modelMap["instance"].([]interface{})[0].(map[string]interface{})["crn"].(string)) + mainModel.Instance = instanceModel + } + } + + if modelMap["role"] != nil && len(modelMap["role"].([]interface{})) > 0 { + roleModel := &secretsmanagerv2.ServiceCredentialsSourceServiceRole{} + if modelMap["role"].([]interface{})[0].(map[string]interface{})["crn"].(string) != "" { + roleModel.Crn = core.StringPtr(modelMap["role"].([]interface{})[0].(map[string]interface{})["crn"].(string)) + mainModel.Role = roleModel + } + } + + if modelMap["parameters"] != nil { + mainModel.Parameters = &secretsmanagerv2.ServiceCredentialsSourceServiceParameters{} + parametersMap := modelMap["parameters"].(map[string]interface{}) + for k, v := range parametersMap { + if k == "serviceid_crn" { + serviceIdCrn := v.(string) + mainModel.Parameters.ServiceidCrn = &serviceIdCrn + } else if v == "true" || v == "false" { + b, _ := strconv.ParseBool(v.(string)) + mainModel.Parameters.SetProperty(k, b) + } else { + mainModel.Parameters.SetProperty(k, v) + } + } + } + return mainModel, nil +} + +func resourceIbmSmServiceCredentialsSecretRotationPolicyToMap(modelIntf secretsmanagerv2.RotationPolicyIntf) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + model := modelIntf.(*secretsmanagerv2.RotationPolicy) + if model.AutoRotate != nil { + modelMap["auto_rotate"] = model.AutoRotate + } + if model.Interval != nil { + modelMap["interval"] = flex.IntValue(model.Interval) + } + if model.Unit != nil { + modelMap["unit"] = model.Unit + } + return modelMap, nil +} + +func resourceIbmSmServiceCredentialsSecretSourceServiceToMap(sourceService *secretsmanagerv2.ServiceCredentialsSecretSourceService) (map[string]interface{}, error) { + mainModelMap := make(map[string]interface{}) + if sourceService.Instance != nil { + instanceMap := make(map[string]interface{}) + instanceModel := sourceService.Instance + if instanceModel.Crn != nil { + instanceMap["crn"] = instanceModel.Crn + } + mainModelMap["instance"] = []map[string]interface{}{instanceMap} + } + + if sourceService.Role != nil { + roleMap := make(map[string]interface{}) + roleModel := sourceService.Role + if roleModel.Crn != nil { + roleMap["crn"] = roleModel.Crn + } + mainModelMap["role"] = []map[string]interface{}{roleMap} + } + + if sourceService.Iam != nil { + iamMap := make(map[string]interface{}) + iamModel := sourceService.Iam + + // apikey + if iamModel.Apikey != nil { + iamApikeyMap := make(map[string]interface{}) + iamApikeyModel := iamModel.Apikey + if iamApikeyModel.Name != nil { + iamApikeyMap["name"] = iamApikeyModel.Name + } + if iamApikeyModel.Description != nil { + iamApikeyMap["description"] = iamApikeyModel.Description + } + iamMap["apikey"] = []map[string]interface{}{iamApikeyMap} + } + + // role + if iamModel.Role != nil { + iamRoleMap := make(map[string]interface{}) + iamRoleModel := iamModel.Role + if iamRoleModel.Crn != nil { + iamRoleMap["crn"] = iamRoleModel.Crn + } + iamMap["role"] = []map[string]interface{}{iamRoleMap} + } + + // service id + if iamModel.Serviceid != nil { + iamServiceidMap := make(map[string]interface{}) + iamServiceidModel := iamModel.Serviceid + if iamServiceidModel.Crn != nil { + iamServiceidMap["crn"] = iamServiceidModel.Crn + } + iamMap["serviceid"] = []map[string]interface{}{iamServiceidMap} + } + + mainModelMap["iam"] = []map[string]interface{}{iamMap} + + } + + if sourceService.ResourceKey != nil { + resourceKeyMap := make(map[string]interface{}) + resourceKeyModel := sourceService.ResourceKey + if resourceKeyModel.Crn != nil { + resourceKeyMap["crn"] = resourceKeyModel.Crn + } + if resourceKeyModel.Name != nil { + resourceKeyMap["name"] = resourceKeyModel.Name + } + mainModelMap["resource_key"] = []map[string]interface{}{resourceKeyMap} + } + + if sourceService.Parameters != nil { + parametersMap := sourceService.Parameters.GetProperties() + for k, v := range parametersMap { + parametersMap[k] = fmt.Sprint(v) + } + if sourceService.Parameters.ServiceidCrn != nil { + if len(parametersMap) == 0 { + parametersMap = make(map[string]interface{}) + } + parametersMap["serviceid_crn"] = sourceService.Parameters.ServiceidCrn + } + mainModelMap["parameters"] = parametersMap + } + + return mainModelMap, nil +} diff --git a/ibm/service/secretsmanager/resource_ibm_sm_service_credentilas_secret_test.go b/ibm/service/secretsmanager/resource_ibm_sm_service_credentilas_secret_test.go new file mode 100644 index 0000000000..7de340208c --- /dev/null +++ b/ibm/service/secretsmanager/resource_ibm_sm_service_credentilas_secret_test.go @@ -0,0 +1,335 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package secretsmanager_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/secrets-manager-go-sdk/v2/secretsmanagerv2" +) + +var serviceCredentialsSecretName = "terraform-test-sc-secret" +var modifiedServiceCredentialsSecretName = "modified-terraform-test-sc-secret" +var serviceCredentialsParameters = `{"HMAC":"true"}` +var serviceCredentialsParametersWithServiceId = `{"serviceid_crn": ibm_iam_service_id.ibm_iam_service_id_instance.crn}` +var serviceCredentialsTtl = "172800" +var modifiedServiceCredentialsTtl = "6048000" +var serviceCredentialsRoleCrn = "crn:v1:bluemix:public:iam::::serviceRole:Writer" + +func TestAccIbmSmServiceCredentialsSecretBasic(t *testing.T) { + resourceName := "ibm_sm_service_credentials_secret.sm_service_credentials_secret_basic" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmSmServiceCredentialsSecretDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: serviceCredentialsSecretConfigBasic(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet(resourceName, "secret_id"), + resource.TestCheckResourceAttrSet(resourceName, "created_by"), + resource.TestCheckResourceAttrSet(resourceName, "created_at"), + resource.TestCheckResourceAttrSet(resourceName, "updated_at"), + resource.TestCheckResourceAttrSet(resourceName, "crn"), + resource.TestCheckResourceAttrSet(resourceName, "downloaded"), + resource.TestCheckResourceAttr(resourceName, "state", "1"), + resource.TestCheckResourceAttr(resourceName, "versions_total", "1"), + ), + }, + resource.TestStep{ + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"ttl"}, + }, + }, + }) +} + +func TestAccIbmSmServiceCredentialsSecretAllArgs(t *testing.T) { + resourceName := "ibm_sm_service_credentials_secret.sm_service_credentials_secret" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmSmServiceCredentialsSecretDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: serviceCredentialsSecretConfigAllArgs(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmSmServiceCredentialsSecretCreated(resourceName), + resource.TestCheckResourceAttrSet(resourceName, "secret_id"), + resource.TestCheckResourceAttrSet(resourceName, "created_by"), + resource.TestCheckResourceAttrSet(resourceName, "created_at"), + resource.TestCheckResourceAttrSet(resourceName, "updated_at"), + resource.TestCheckResourceAttrSet(resourceName, "crn"), + resource.TestCheckResourceAttrSet(resourceName, "downloaded"), + resource.TestCheckResourceAttrSet(resourceName, "next_rotation_date"), + resource.TestCheckResourceAttr(resourceName, "state", "1"), + resource.TestCheckResourceAttr(resourceName, "versions_total", "1"), + ), + }, + resource.TestStep{ + Config: serviceCredentialsSecretConfigUpdated(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmSmServiceCredentialsSecretUpdated(resourceName), + ), + }, + resource.TestStep{ + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"ttl"}, + }, + }, + }) +} + +func TestAccIbmSmServiceCredentialsSecretAllArgsWithExistingServiceId(t *testing.T) { + resourceName := "ibm_sm_service_credentials_secret.sm_service_credentials_secret_service_id" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmSmServiceCredentialsSecretDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: serviceCredentialsSecretConfigAllArgsWithExistingServiceId(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmSmServiceCredentialsSecretCreated(resourceName), + resource.TestCheckResourceAttrSet(resourceName, "secret_id"), + resource.TestCheckResourceAttrSet(resourceName, "created_by"), + resource.TestCheckResourceAttrSet(resourceName, "created_at"), + resource.TestCheckResourceAttrSet(resourceName, "updated_at"), + resource.TestCheckResourceAttrSet(resourceName, "crn"), + resource.TestCheckResourceAttrSet(resourceName, "downloaded"), + resource.TestCheckResourceAttrSet(resourceName, "next_rotation_date"), + resource.TestCheckResourceAttr(resourceName, "state", "1"), + resource.TestCheckResourceAttr(resourceName, "versions_total", "1"), + ), + }, + resource.TestStep{ + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"ttl"}, + }, + }, + }) +} + +var serviceCredentialsSecretBasicConfigFormat = ` + resource "ibm_sm_service_credentials_secret" "sm_service_credentials_secret_basic" { + instance_id = "%s" + region = "%s" + name = "%s" + source_service { + instance { + crn = "%s" + } + role { + crn = "%s" + } + } + ttl = "%s" + }` + +var serviceCredentialsSecretFullConfigFormat = ` + resource "ibm_sm_service_credentials_secret" "sm_service_credentials_secret" { + instance_id = "%s" + region = "%s" + name = "%s" + description = "%s" + labels = ["%s"] + source_service { + instance { + crn = "%s" + } + parameters = %s + role { + crn = "%s" + } + } + ttl = "%s" + custom_metadata = %s + secret_group_id = "default" + rotation %s + }` + +var serviceCredentialsSecretFullConfigFormatWithExistingServiceId = ` + resource "ibm_sm_service_credentials_secret" "sm_service_credentials_secret_service_id" { + instance_id = "%s" + region = "%s" + name = "%s" + description = "%s" + labels = ["%s"] + source_service { + instance { + crn = "%s" + } + parameters = %s + role { + crn = "%s" + } + } + ttl = "%s" + custom_metadata = %s + secret_group_id = "default" + rotation %s + }` + +func iamServiceIdConfig() string { + return fmt.Sprintf(` + resource "ibm_iam_service_id" "ibm_iam_service_id_instance" { + name = "service-id-terraform-tests-sc" + }`) +} + +func serviceCredentialsSecretConfigBasic() string { + return fmt.Sprintf(serviceCredentialsSecretBasicConfigFormat, acc.SecretsManagerInstanceID, acc.SecretsManagerInstanceRegion, + serviceCredentialsSecretName, acc.SecretsManagerServiceCredentialsCosCrn, serviceCredentialsRoleCrn, serviceCredentialsTtl) +} + +func serviceCredentialsSecretConfigAllArgs() string { + return fmt.Sprintf(serviceCredentialsSecretFullConfigFormat, acc.SecretsManagerInstanceID, acc.SecretsManagerInstanceRegion, + serviceCredentialsSecretName, description, label, acc.SecretsManagerServiceCredentialsCosCrn, serviceCredentialsParameters, serviceCredentialsRoleCrn, serviceCredentialsTtl, customMetadata, rotationPolicy) +} + +func serviceCredentialsSecretConfigAllArgsWithExistingServiceId() string { + return iamServiceIdConfig() + fmt.Sprintf(serviceCredentialsSecretFullConfigFormatWithExistingServiceId, acc.SecretsManagerInstanceID, acc.SecretsManagerInstanceRegion, + serviceCredentialsSecretName, description, label, acc.SecretsManagerServiceCredentialsCosCrn, serviceCredentialsParametersWithServiceId, serviceCredentialsRoleCrn, serviceCredentialsTtl, customMetadata, rotationPolicy) +} + +func serviceCredentialsSecretConfigUpdated() string { + return fmt.Sprintf(serviceCredentialsSecretFullConfigFormat, acc.SecretsManagerInstanceID, acc.SecretsManagerInstanceRegion, + modifiedServiceCredentialsSecretName, modifiedDescription, modifiedLabel, acc.SecretsManagerServiceCredentialsCosCrn, serviceCredentialsParameters, serviceCredentialsRoleCrn, + modifiedServiceCredentialsTtl, modifiedCustomMetadata, modifiedRotationPolicy) +} + +func testAccCheckIbmSmServiceCredentialsSecretCreated(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + serviceCredentialsSecretIntf, err := getSecret(s, n) + if err != nil { + return err + } + secret := serviceCredentialsSecretIntf.(*secretsmanagerv2.ServiceCredentialsSecret) + + if err := verifyAttr(*secret.Name, serviceCredentialsSecretName, "secret name"); err != nil { + return err + } + if err := verifyAttr(*secret.Description, description, "secret description"); err != nil { + return err + } + if len(secret.Labels) != 1 { + return fmt.Errorf("Wrong number of labels: %d", len(secret.Labels)) + } + if err := verifyAttr(secret.Labels[0], label, "label"); err != nil { + return err + } + if err := verifyJsonAttr(secret.CustomMetadata, customMetadata, "custom metadata"); err != nil { + return err + } + if err := verifyAttr(getAutoRotate(secret.Rotation), "true", "auto_rotate"); err != nil { + return err + } + if err := verifyAttr(getRotationUnit(secret.Rotation), "day", "rotation unit"); err != nil { + return err + } + if err := verifyAttr(getRotationInterval(secret.Rotation), "1", "rotation interval"); err != nil { + return err + } + if err := verifyAttr(*secret.TTL, serviceCredentialsTtl, "ttl"); err != nil { + return err + } + if err := verifyAttr(*secret.SourceService.Instance.Crn, acc.SecretsManagerServiceCredentialsCosCrn, "source_service.Instance.Crn"); err != nil { + return err + } + if err := verifyAttr(*secret.SourceService.Role.Crn, serviceCredentialsRoleCrn, "source_service.Role.Crn"); err != nil { + return err + } + if err := verifyAttr(*secret.Credentials.IamRoleCrn, serviceCredentialsRoleCrn, "credentials.IamRoleCrn"); err != nil { + return err + } + return nil + } +} + +func testAccCheckIbmSmServiceCredentialsSecretUpdated(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + serviceCredentialsSecretIntf, err := getSecret(s, n) + if err != nil { + return err + } + secret := serviceCredentialsSecretIntf.(*secretsmanagerv2.ServiceCredentialsSecret) + + if err := verifyAttr(*secret.Name, modifiedServiceCredentialsSecretName, "secret name"); err != nil { + return err + } + if err := verifyAttr(*secret.Description, modifiedDescription, "secret description after update"); err != nil { + return err + } + if len(secret.Labels) != 1 { + return fmt.Errorf("Wrong number of labels after update: %d", len(secret.Labels)) + } + if err := verifyAttr(secret.Labels[0], modifiedLabel, "label after update"); err != nil { + return err + } + if err := verifyJsonAttr(secret.CustomMetadata, modifiedCustomMetadata, "custom metadata after update"); err != nil { + return err + } + if err := verifyAttr(*secret.TTL, modifiedServiceCredentialsTtl, "ttl after update"); err != nil { + return err + } + if err := verifyAttr(getAutoRotate(secret.Rotation), "true", "auto_rotate after update"); err != nil { + return err + } + if err := verifyAttr(getRotationUnit(secret.Rotation), "month", "rotation unit after update"); err != nil { + return err + } + if err := verifyAttr(getRotationInterval(secret.Rotation), "2", "rotation interval after update"); err != nil { + return err + } + return nil + } +} + +func testAccCheckIbmSmServiceCredentialsSecretDestroy(s *terraform.State) error { + secretsManagerClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SecretsManagerV2() + if err != nil { + return err + } + + secretsManagerClient = getClientWithInstanceEndpointTest(secretsManagerClient) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_sm_service_credentials_secret" { + continue + } + + getSecretOptions := &secretsmanagerv2.GetSecretOptions{} + + id := strings.Split(rs.Primary.ID, "/") + secretId := id[2] + getSecretOptions.SetID(secretId) + + // Try to find the key + _, response, err := secretsManagerClient.GetSecret(getSecretOptions) + + if err == nil { + return fmt.Errorf("ServiceCredentialsSecret still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for ServiceCredentialsSecret (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/secretsmanager/utils.go b/ibm/service/secretsmanager/utils.go index a00f44c9af..07a23380be 100644 --- a/ibm/service/secretsmanager/utils.go +++ b/ibm/service/secretsmanager/utils.go @@ -17,13 +17,14 @@ import ( ) const ( - ArbitrarySecretType = "arbitrary" - UsernamePasswordSecretType = "username_password" - IAMCredentialsSecretType = "iam_credentials" - KvSecretType = "kv" - ImportedCertSecretType = "imported_cert" - PublicCertSecretType = "public_cert" - PrivateCertSecretType = "private_cert" + ArbitrarySecretType = "arbitrary" + UsernamePasswordSecretType = "username_password" + IAMCredentialsSecretType = "iam_credentials" + ServiceCredentialsSecretType = "service_credentials" + KvSecretType = "kv" + ImportedCertSecretType = "imported_cert" + PublicCertSecretType = "public_cert" + PrivateCertSecretType = "private_cert" ) func getRegion(originalClient *secretsmanagerv2.SecretsManagerV2, d *schema.ResourceData) string { diff --git a/website/docs/d/sm_service_credentials_secret.html.markdown b/website/docs/d/sm_service_credentials_secret.html.markdown new file mode 100644 index 0000000000..bef56d1469 --- /dev/null +++ b/website/docs/d/sm_service_credentials_secret.html.markdown @@ -0,0 +1,156 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_sm_service_credentials_secret" +description: |- + Get information about ServiceCredentialsSecret +subcategory: "Secrets Manager" +--- + +# ibm_sm_service_credentials_secret + +Provides a read-only data source for a service credentials secret. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. +The data source can be defined by providing the secret ID or the secret and secret group names. + +## Example Usage + +By secret id +```hcl +data "ibm_sm_service_credentials_secret" "service_credentials_secret" { + instance_id = ibm_resource_instance.sm_instance.guid + region = "us-south" + secret_id = "0b5571f7-21e6-42b7-91c5-3f5ac9793a46" +} +``` + +By secret name and group name +```hcl +data "ibm_sm_service_credentials_secret" "service_credentials_secret" { + instance_id = ibm_resource_instance.sm_instance.guid + region = "us-south" + name = "secret-name" + secret_group_name = "group-name" +} +``` + +### Example to access resource credentials using credentials attribute: + +```terraform +data "ibm_sm_service_credentials_secret" "service_credentials_secret" { + instance_id = ibm_resource_instance.sm_instance.guid + region = "us-south" + secret_id = "0b5571f7-21e6-42b7-91c5-3f5ac9793a46" +} +output "access_key_id" { + value = data.ibm_sm_service_credentials_secret.service_credentials_secret.credentials["cos_hmac_keys.access_key_id"] +} +output "secret_access_key" { + value = data.ibm_sm_service_credentials_secret.service_credentials_secret.credentials["cos_hmac_keys.secret_access_key"] +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `instance_id` - (Required, Forces new resource, String) The GUID of the Secrets Manager instance. +* `region` - (Optional, Forces new resource, String) The region of the Secrets Manager instance. If not provided defaults to the region defined in the IBM provider configuration. +* `endpoint_type` - (Optional, String) - The endpoint type. If not provided the endpoint type is determined by the `visibility` argument provided in the provider configuration. + * Constraints: Allowable values are: `private`, `public`. +* `secret_id` - (Optional, String) The ID of the secret. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/`. +* `name` - (Optional, String) The human-readable name of your secret. To be used in combination with `secret_group_name`. + * Constraints: The maximum length is `256` characters. The minimum length is `2` characters. The value must match regular expression `^[A-Za-z0-9][A-Za-z0-9]*(?:_*-*\\.*[A-Za-z0-9]+)*$`. +* `secret_group_name` - (Optional, String) The name of your existing secret group. To be used in combination with `name`. + * Constraints: The maximum length is `64` characters. The minimum length is `2` characters. The value must match regular expression `/(.*?)/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `created_at` - (String) The date when a resource was created. The date format follows RFC 3339. + +* `created_by` - (String) The unique identifier that is associated with the entity that created the secret. + * Constraints: The maximum length is `128` characters. The minimum length is `4` characters. + +* `credentials` - (List) The properties of the service credentials secret payload. + Nested scheme for **credentials**: + * `apikey` - (String) The API key that is generated for this secret. + * `cos_hmac_keys` - (String) The Cloud Object Storage HMAC keys that are returned after you create a service credentials secret. + Nested scheme for **cos_hmac_keys**: + * `access_key_id` - (String) The access key ID for Cloud Object Storage HMAC credentials. + * `secret_access_key` - (String) The secret access key ID for Cloud Object Storage HMAC credentials. + * `endpoints` - (String) The endpoints that are returned after you create a service credentials secret. + * `iam_apikey_description` - (String) The description of the generated IAM API key. + * `iam_apikey_name` - (String) The name of the generated IAM API key. + * `iam_role_crn` - (String) The IAM role CRN that is returned after you create a service credentials secret. + * `iam_serviceid_crn` - (String) The IAM serviceId CRN that is returned after you create a service credentials secret. + * `resource_instance_id` - (String) The resource instance CRN that is returned after you create a service credentials secret. + +* `crn` - (String) A CRN that uniquely identifies an IBM Cloud resource. + * Constraints: The maximum length is `512` characters. The minimum length is `9` characters. The value must match regular expression `/^crn:v[0-9](:([A-Za-z0-9-._~!$&'()*+,;=@\/]|%[0-9A-Z]{2})*){8}$/`. + +* `custom_metadata` - (Map) The secret metadata that a user can customize. + +* `description` - (String) An extended description of your secret.To protect your privacy, do not use personal data, such as your name or location, as a description for your secret group. + * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/(.*?)/`. + +* `downloaded` - (Boolean) Indicates whether the secret data that is associated with a secret version was retrieved in a call to the service API. + +* `labels` - (List) Labels that you can use to search for secrets in your instance.Up to 30 labels can be created. + * Constraints: The list items must match regular expression `/(.*?)/`. The maximum length is `30` items. The minimum length is `0` items. + +* `locks_total` - (Integer) The number of locks of the secret. + * Constraints: The maximum value is `1000`. The minimum value is `0`. + +* `name` - (String) The human-readable name of your secret. + * Constraints: The maximum length is `256` characters. The minimum length is `2` characters. + +* `next_rotation_date` - (String) The date that the secret is scheduled for automatic rotation.The service automatically creates a new version of the secret on its next rotation date. This field exists only for secrets that have an existing rotation policy. + +* `rotation` - (List) Determines whether Secrets Manager rotates your secrets automatically. + Nested scheme for **rotation**: + * `auto_rotate` - (Boolean) Determines whether Secrets Manager rotates your secret automatically.Default is `false`. If `auto_rotate` is set to `true` the service rotates your secret based on the defined interval. + * `interval` - (Integer) The length of the secret rotation time interval. + * Constraints: The minimum value is `1`. + * `unit` - (String) The units for the secret rotation time interval. + * Constraints: Allowable values are: `day`, `month`. + +* `secret_group_id` - (String) A v4 UUID identifier, or `default` secret group. + * Constraints: The maximum length is `36` characters. The minimum length is `7` characters. The value must match regular expression `/^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|default)$/`. + +* `secret_type` - (String) The secret type. Supported types are arbitrary, certificates (imported, public, and private), IAM credentials, key-value, and user credentials. + * Constraints: Allowable values are: `arbitrary`, `imported_cert`, `public_cert`, `iam_credentials`, `kv`, `username_password`, `private_cert`. + +* `source_service` - (List) The properties required for creating the service credentials for the specified source service instance. + Nested scheme for **source_service**: + * `iam` - (List) The source service IAM data is returned in case IAM credentials where created for this secret. + Nested scheme for **iam**: + * `apikey` - (String) The IAM apikey metadata for the IAM credentials that were generated. + Nested scheme for **apikey**: + * `name` - (String) The IAM API key name for the generated service credentials. + * `description` - (String) The IAM API key description for the generated service credentials. + * `role` - (String) The IAM role for the generate service credentials. + Nested scheme for **role**: + * `crn` - (String) The IAM role CRN assigned to the generated service credentials. + * `serviceid` - (String) The IAM serviceid for the generated service credentials. + Nested scheme for **serviceid**: + * `crn` - (String) The IAM Service ID CRN. + * `resource_key` - (List) The source service resource key data of the generated service credentials. + Nested scheme for **resource_key**: + * `crn` - (String) The resource key CRN of the generated service credentials. + * `name` - (String) The resource key name of the generated service credentials. + +* `state` - (Integer) The secret state that is based on NIST SP 800-57. States are integers and correspond to the `Pre-activation = 0`, `Active = 1`, `Suspended = 2`, `Deactivated = 3`, and `Destroyed = 5` values. + * Constraints: Allowable values are: `0`, `1`, `2`, `3`, `5`. + +* `state_description` - (String) A text representation of the secret state. + * Constraints: Allowable values are: `pre_activation`, `active`, `suspended`, `deactivated`, `destroyed`. + +* `ttl` - (String) The time-to-live (TTL) or lease duration to assign to generated credentials. The TTL defines for how long generated credentials remain valid. The value should be a string that specifies the number of seconds. Minimum duration is 86400 (1 day). Maximum is 7776000 seconds (90 days). + * Constraints: The maximum length is `7` characters. The minimum length is `2` characters. + +* `updated_at` - (String) The date when a resource was recently modified. The date format follows RFC 3339. + +* `versions_total` - (Integer) The number of versions of the secret. + * Constraints: The maximum value is `50`. The minimum value is `0`. + diff --git a/website/docs/d/sm_service_credentials_secret_metadata.html.markdown b/website/docs/d/sm_service_credentials_secret_metadata.html.markdown new file mode 100644 index 0000000000..94b9d8d648 --- /dev/null +++ b/website/docs/d/sm_service_credentials_secret_metadata.html.markdown @@ -0,0 +1,113 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_sm_service_credentials_secret_metadata" +description: |- + Get information about ServiceCredentialsSecretMetadata +subcategory: "Secrets Manager" +--- + +# ibm_sm_service_credentials_secret_metadata + +Provides a read-only data source for the metadata of an service credentials secret. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. + + +## Example Usage + +```hcl +data "ibm_sm_service_credentials_secret_metadata" "service_credentials_secret_metadata" { + instance_id = ibm_resource_instance.sm_instance.guid + region = "us-south" + secret_id = "0b5571f7-21e6-42b7-91c5-3f5ac9793a46" +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your data source. + +* `instance_id` - (Required, Forces new resource, String) The GUID of the Secrets Manager instance. +* `region` - (Optional, Forces new resource, String) The region of the Secrets Manager instance. If not provided defaults to the region defined in the IBM provider configuration. +* `endpoint_type` - (Optional, String) - The endpoint type. If not provided the endpoint type is determined by the `visibility` argument provided in the provider configuration. + * Constraints: Allowable values are: `private`, `public`. +* `secret_id` - (Optional, String) The ID of the secret. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/`. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your data source is created. + +* `id` - The unique identifier of the data source. + +* `created_at` - (String) The date when a resource was created. The date format follows RFC 3339. + +* `created_by` - (String) The unique identifier that is associated with the entity that created the secret. + * Constraints: The maximum length is `128` characters. The minimum length is `4` characters. + +* `crn` - (String) A CRN that uniquely identifies an IBM Cloud resource. + * Constraints: The maximum length is `512` characters. The minimum length is `9` characters. The value must match regular expression `/^crn:v[0-9](:([A-Za-z0-9-._~!$&'()*+,;=@\/]|%[0-9A-Z]{2})*){8}$/`. + +* `custom_metadata` - (Map) The secret metadata that a user can customize. + +* `description` - (String) An extended description of your secret.To protect your privacy, do not use personal data, such as your name or location, as a description for your secret group. + * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/(.*?)/`. + +* `downloaded` - (Boolean) Indicates whether the secret data that is associated with a secret version was retrieved in a call to the service API. + +* `labels` - (List) Labels that you can use to search for secrets in your instance.Up to 30 labels can be created. + * Constraints: The list items must match regular expression `/(.*?)/`. The maximum length is `30` items. The minimum length is `0` items. + +* `locks_total` - (Integer) The number of locks of the secret. + * Constraints: The maximum value is `1000`. The minimum value is `0`. + +* `name` - (String) The human-readable name of your secret. + * Constraints: The maximum length is `256` characters. The minimum length is `2` characters. + +* `next_rotation_date` - (String) The date that the secret is scheduled for automatic rotation.The service automatically creates a new version of the secret on its next rotation date. This field exists only for secrets that have an existing rotation policy. + +* `rotation` - (List) Determines whether Secrets Manager rotates your secrets automatically. + Nested scheme for **rotation**: + * `auto_rotate` - (Boolean) Determines whether Secrets Manager rotates your secret automatically.Default is `false`. If `auto_rotate` is set to `true` the service rotates your secret based on the defined interval. + * `interval` - (Integer) The length of the secret rotation time interval. + * Constraints: The minimum value is `1`. + * `unit` - (String) The units for the secret rotation time interval. + * Constraints: Allowable values are: `day`, `month`. + +* `secret_group_id` - (String) A v4 UUID identifier, or `default` secret group. + * Constraints: The maximum length is `36` characters. The minimum length is `7` characters. The value must match regular expression `/^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|default)$/`. + +* `secret_type` - (String) The secret type. Supported types are arbitrary, certificates (imported, public, and private), IAM credentials, key-value, and user credentials. + * Constraints: Allowable values are: `arbitrary`, `imported_cert`, `public_cert`, `iam_credentials`, `kv`, `username_password`, `private_cert`. + +* `source_service` - (List) The properties required for creating the service credentials for the specified source service instance. + Nested scheme for **source_service**: + * `iam` - (List) The source service IAM data is returned in case IAM credentials where created for this secret. + Nested scheme for **iam**: + * `apikey` - (String) The IAM apikey metadata for the IAM credentials that were generated. + Nested scheme for **apikey**: + * `name` - (String) The IAM API key name for the generated service credentials. + * `description` - (String) The IAM API key description for the generated service credentials. + * `role` - (String) The IAM role for the generate service credentials. + Nested scheme for **role**: + * `crn` - (String) The IAM role CRN assigned to the generated service credentials. + * `serviceid` - (String) The IAM serviceid for the generated service credentials. + Nested scheme for **serviceid**: + * `crn` - (String) The IAM Service ID CRN. + * `resource_key` - (List) The source service resource key data of the generated service credentials. + Nested scheme for **resource_key**: + * `crn` - (String) The resource key CRN of the generated service credentials. + * `name` - (String) The resource key name of the generated service credentials. + +* `state` - (Integer) The secret state that is based on NIST SP 800-57. States are integers and correspond to the `Pre-activation = 0`, `Active = 1`, `Suspended = 2`, `Deactivated = 3`, and `Destroyed = 5` values. + * Constraints: Allowable values are: `0`, `1`, `2`, `3`, `5`. + +* `state_description` - (String) A text representation of the secret state. + * Constraints: Allowable values are: `pre_activation`, `active`, `suspended`, `deactivated`, `destroyed`. + +* `ttl` - (String) The time-to-live (TTL) or lease duration to assign to generated credentials. The TTL defines for how long generated credentials remain valid. The value should be a string that specifies the number of seconds. Minimum duration is 86400 (1 day). Maximum is 7776000 seconds (90 days). + * Constraints: The maximum length is `7` characters. The minimum length is `2` characters. + +* `updated_at` - (String) The date when a resource was recently modified. The date format follows RFC 3339. + +* `versions_total` - (Integer) The number of versions of the secret. + * Constraints: The maximum value is `50`. The minimum value is `0`. + diff --git a/website/docs/r/sm_service_credentials_secret.html.markdown b/website/docs/r/sm_service_credentials_secret.html.markdown new file mode 100644 index 0000000000..cdf60c3e9f --- /dev/null +++ b/website/docs/r/sm_service_credentials_secret.html.markdown @@ -0,0 +1,222 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_sm_service_credentials_secret" +description: |- + Manages ServiceCredentialsSecret. +subcategory: "Secrets Manager" +--- + +# ibm_sm_service_credentials_secret + +Provides a resource for ServiceCredentialsSecret. This allows ServiceCredentialsSecret to be created, updated and deleted. + +## Example Usage + +```hcl +resource "ibm_sm_service_credentials_secret" "sm_service_credentials_secret" { + instance_id = ibm_resource_instance.sm_instance.guid + region = "us-south" + name = "secret-name" + custom_metadata = {"key":"value"} + description = "Extended description for this secret." + labels = ["my-label"] + rotation { + auto_rotate = true + interval = 1 + unit = "day" + } + secret_group_id = ibm_sm_secret_group.sm_secret_group.secret_group_id + source_service { + instance { + crn = "crn:v1:staging:public:cloud-object-storage:global:a/111f5fb10986423e9saa8512f1db7e65:111133c8-49ea-41xe-8c40-122038246f5b::" + } + role { + crn = "crn:v1:bluemix:public:iam::::serviceRole:Writer" + } + parameters = {"HMAC": true} + } + ttl = "1800" +} +``` + +### Example to access resource credentials using credentials attribute: + +```terraform +resource "ibm_sm_service_credentials_secret" "sm_service_credentials_secret" { + region = "us-south" + name = "secret-name" + source_service { + instance { + crn = "crn:v1:staging:public:cloud-object-storage:global:a/111f5fb10986423e9saa8512f1db7e65:111133c8-49ea-41xe-8c40-122038246f5b::" + } + role { + crn = "crn:v1:bluemix:public:iam::::serviceRole:Writer" + } + parameters = {"HMAC": true} + } + ttl = "1800" +} + +output "access_key_id" { + value = ibm_sm_service_credentials_secret.sm_service_credentials_secret.credentials["cos_hmac_keys.access_key_id"] +} +output "secret_access_key" { + value = ibm_sm_service_credentials_secret.sm_service_credentials_secret.credentials["cos_hmac_keys.secret_access_key"] +} +``` + +## Argument Reference + +Review the argument reference that you can specify for your resource. + +* `instance_id` - (Required, Forces new resource, String) The GUID of the Secrets Manager instance. +* `region` - (Optional, Forces new resource, String) The region of the Secrets Manager instance. If not provided defaults to the region defined in the IBM provider configuration. +* `endpoint_type` - (Optional, String) - The endpoint type. If not provided the endpoint type is determined by the `visibility` argument provided in the provider configuration. + * Constraints: Allowable values are: `private`, `public`. +* `name` - (Required, String) The human-readable name of your secret. + * Constraints: The maximum length is `256` characters. The minimum length is `2` characters. The value must match regular expression `^[A-Za-z0-9][A-Za-z0-9]*(?:_*-*\\.*[A-Za-z0-9]+)*$`. +* `custom_metadata` - (Optional, Map) The secret metadata that a user can customize. +* `description` - (Optional, String) An extended description of your secret.To protect your privacy, do not use personal data, such as your name or location, as a description for your secret group. + * Constraints: The maximum length is `1024` characters. The minimum length is `0` characters. The value must match regular expression `/(.*?)/`. +* `labels` - (Optional, List) Labels that you can use to search for secrets in your instance.Up to 30 labels can be created. + * Constraints: The list items must match regular expression `/(.*?)/`. The maximum length is `30` items. The minimum length is `0` items. +* `rotation` - (Optional, List) Determines whether Secrets Manager rotates your secrets automatically. +Nested scheme for **rotation**: + * `auto_rotate` - (Optional, Boolean) Determines whether Secrets Manager rotates your secret automatically.Default is `false`. If `auto_rotate` is set to `true` the service rotates your secret based on the defined interval. + * `interval` - (Optional, Integer) The length of the secret rotation time interval. + * Constraints: The minimum value is `1`. + * `unit` - (Optional, String) The units for the secret rotation time interval. + * Constraints: Allowable values are: `day`, `month`. +* `secret_group_id` - (Optional, Forces new resource, String) A v4 UUID identifier, or `default` secret group. + * Constraints: The maximum length is `36` characters. The minimum length is `7` characters. The value must match regular expression `/^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|default)$/`. +* `source_service` - (Optional, List) The properties required for creating the service credentials for the specified source service instance. +Nested scheme for **source_service**: + * `instance` - (Optional, List) The source service instance identifier. + Nested scheme for **instance**: + * `crn` - (Optional, String) A CRN that uniquely identifies a service credentials source. + * `role` - (Optional, List) The service-specific custom role object, CRN role is accepted. Refer to the service’s documentation for supported roles. + Nested scheme for **role**: + * `crn` - (Optional, String) The service role CRN. + * `parameters` - (Optional, List) Configuration options represented as key-value pairs. Service-defined options are used in the generation of credentials for some services. For example, Cloud Object Storage accepts the optional boolean parameter HMAC for creating specific kind of credentials. +* `ttl` - (Required, String) The time-to-live (TTL) or lease duration to assign to generated credentials. The TTL defines for how long generated credentials remain valid. The value should be a string that specifies the number of seconds. Minimum duration is 86400 (1 day). Maximum is 7776000 seconds (90 days). + * Constraints: The maximum length is `7` characters. The minimum length is `2` characters. + +## Attribute Reference + +In addition to all argument references listed, you can access the following attribute references after your resource is created. + +* `secret_id` - The unique identifier of the ServiceCredentialsSecret. +* `created_at` - (String) The date when a resource was created. The date format follows RFC 3339. +* `created_by` - (String) The unique identifier that is associated with the entity that created the secret. + * Constraints: The maximum length is `128` characters. The minimum length is `4` characters. +* `credentials` - (List) The properties of the service credentials secret payload. + Nested scheme for **credentials**: + * `apikey` - (String) The API key that is generated for this secret. + * `cos_hmac_keys` - (String) The Cloud Object Storage HMAC keys that are returned after you create a service credentials secret. + Nested scheme for **cos_hmac_keys**: + * `access_key_id` - (String) The access key ID for Cloud Object Storage HMAC credentials. + * `secret_access_key` - (String) The secret access key ID for Cloud Object Storage HMAC credentials. + * `endpoints` - (String) The endpoints that are returned after you create a service credentials secret. + * `iam_apikey_description` - (String) The description of the generated IAM API key. + * `iam_apikey_name` - (String) The name of the generated IAM API key. + * `iam_role_crn` - (String) The IAM role CRN that is returned after you create a service credentials secret. + * `iam_serviceid_crn` - (String) The IAM serviceId CRN that is returned after you create a service credentials secret. + * `resource_instance_id` - (String) The resource instance CRN that is returned after you create a service credentials secret. +* `crn` - (String) A CRN that uniquely identifies an IBM Cloud resource. + * Constraints: The maximum length is `512` characters. The minimum length is `9` characters. The value must match regular expression `/^crn:v[0-9](:([A-Za-z0-9-._~!$&'()*+,;=@\/]|%[0-9A-Z]{2})*){8}$/`. +* `downloaded` - (Boolean) Indicates whether the secret data that is associated with a secret version was retrieved in a call to the service API. +* `locks_total` - (Integer) The number of locks of the secret. + * Constraints: The maximum value is `1000`. The minimum value is `0`. +* `next_rotation_date` - (String) The date that the secret is scheduled for automatic rotation.The service automatically creates a new version of the secret on its next rotation date. This field exists only for secrets that have an existing rotation policy. +* `source_service` - (List) The properties required for creating the service credentials for the specified source service instance. + Nested scheme for **source_service**: + * `iam` - (List) The source service IAM data is returned in case IAM credentials where created for this secret. + Nested scheme for **iam**: + * `apikey` - (String) The IAM apikey metadata for the IAM credentials that were generated. + Nested scheme for **apikey**: + * `name` - (String) The IAM API key name for the generated service credentials. + * `description` - (String) The IAM API key description for the generated service credentials. + * `role` - (String) The IAM role for the generate service credentials. + Nested scheme for **role**: + * `crn` - (String) The IAM role CRN assigned to the generated service credentials. + * `serviceid` - (String) The IAM serviceid for the generated service credentials. + Nested scheme for **serviceid**: + * `crn` - (String) The IAM Service ID CRN. + * `resource_key` - (List) The source service resource key data of the generated service credentials. + Nested scheme for **resource_key**: + * `crn` - (String) The resource key CRN of the generated service credentials. + * `name` - (String) The resource key name of the generated service credentials. +* `state` - (Integer) The secret state that is based on NIST SP 800-57. States are integers and correspond to the `Pre-activation = 0`, `Active = 1`, `Suspended = 2`, `Deactivated = 3`, and `Destroyed = 5` values. + * Constraints: Allowable values are: `0`, `1`, `2`, `3`, `5`. +* `state_description` - (String) A text representation of the secret state. + * Constraints: Allowable values are: `pre_activation`, `active`, `suspended`, `deactivated`, `destroyed`. +* `secret_type` - (String) The secret type. Supported types are arbitrary, certificates (imported, public, and private), IAM credentials, key-value, and user credentials. + * Constraints: Allowable values are: `arbitrary`, `imported_cert`, `public_cert`, `iam_credentials`, `kv`, `username_password`, `private_cert`. +* `updated_at` - (String) The date when a resource was recently modified. The date format follows RFC 3339. +* `versions_total` - (Integer) The number of versions of the secret. + * Constraints: The maximum value is `50`. The minimum value is `0`. + +## Provider Configuration + +The IBM Cloud provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and explained below: + +- Static credentials +- Environment variables + +To find which credentials are required for this resource, see the service table [here](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-provider-reference#required-parameters). + +### Static credentials + +You can provide your static credentials by adding the `ibmcloud_api_key`, `iaas_classic_username`, and `iaas_classic_api_key` arguments in the IBM Cloud provider block. + +Usage: +``` +provider "ibm" { + ibmcloud_api_key = "" + iaas_classic_username = "" + iaas_classic_api_key = "" +} +``` + +### Environment variables + +You can provide your credentials by exporting the `IC_API_KEY`, `IAAS_CLASSIC_USERNAME`, and `IAAS_CLASSIC_API_KEY` environment variables, representing your IBM Cloud platform API key, IBM Cloud Classic Infrastructure (SoftLayer) user name, and IBM Cloud infrastructure API key, respectively. + +``` +provider "ibm" {} +``` + +Usage: +``` +export IC_API_KEY="ibmcloud_api_key" +export IAAS_CLASSIC_USERNAME="iaas_classic_username" +export IAAS_CLASSIC_API_KEY="iaas_classic_api_key" +terraform plan +``` + +Note: + +1. Create or find your `ibmcloud_api_key` and `iaas_classic_api_key` [here](https://cloud.ibm.com/iam/apikeys). + - Select `My IBM Cloud API Keys` option from view dropdown for `ibmcloud_api_key` + - Select `Classic Infrastructure API Keys` option from view dropdown for `iaas_classic_api_key` +2. For iaas_classic_username + - Go to [Users](https://cloud.ibm.com/iam/users) + - Click on user. + - Find user name in the `VPN password` section under `User Details` tab + +For more informaton, see [here](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs#authentication). + +## Import + +You can import the `ibm_sm_service_credentials_secret` resource by using `region`, `instance_id`, and `secret_id`. +For more information, see [the documentation](https://cloud.ibm.com/docs/secrets-manager) + +# Syntax +```bash +$ terraform import ibm_sm_service_credentials_secret.sm_service_credentials_secret // +``` + +# Example +```bash +$ terraform import ibm_sm_service_credentials_secret.sm_service_credentials_secret us-east/6ebc4224-e983-496a-8a54-f40a0bfa9175/b49ad24d-81d4-5ebc-b9b9-b0937d1c84d5 +``` From dfb68f89fd8afc6d9d9916ee1bc1bcff1713b515 Mon Sep 17 00:00:00 2001 From: SunithaGudisagar <127872893+SunithaGudisagarIBM1@users.noreply.github.com> Date: Wed, 13 Dec 2023 17:04:25 +0530 Subject: [PATCH 11/14] Feature is snapshot consistency group and Migration PR (#4973) * GO-SDK Updated * ibm_is_snapshot_consistency_group development * Consistency Group changes to Snapshot * Documentation changes for snapshot * SDK changes * Bankup Policy Jobs Changes * included_content development * match_resource_type development * Implemented Documentation Fix * PR review comments incorporated * SDK update * Updated to released SDK --- examples/ibm-is-ng/main.tf | 39 +- go.mod | 4 +- go.sum | 3 + ibm/provider/provider.go | 21 +- .../vpc/data_source_ibm_is_backup_policies.go | 24 +- .../vpc/data_source_ibm_is_backup_policy.go | 35 +- .../data_source_ibm_is_backup_policy_job.go | 211 ++++- .../data_source_ibm_is_backup_policy_jobs.go | 161 +++- .../vpc/data_source_ibm_is_snapshot.go | 66 ++ ...ource_ibm_is_snapshot_consistency_group.go | 589 +++++++++++++ ..._ibm_is_snapshot_consistency_group_test.go | 61 ++ ...urce_ibm_is_snapshot_consistency_groups.go | 369 ++++++++ ...ibm_is_snapshot_consistency_groups_test.go | 61 ++ .../vpc/data_source_ibm_is_snapshots.go | 91 +- .../vpc/resource_ibm_is_backup_policy.go | 79 +- ibm/service/vpc/resource_ibm_is_snapshot.go | 68 ++ ...ource_ibm_is_snapshot_consistency_group.go | 815 ++++++++++++++++++ ..._ibm_is_snapshot_consistency_group_test.go | 166 ++++ ...ource_ibm_is_vpc_dns_resolution_binding.go | 2 +- .../docs/d/is_backup_policies.html.markdown | 8 + website/docs/d/is_backup_policy.html.markdown | 3 + .../docs/d/is_backup_policy_job.html.markdown | 17 + .../d/is_backup_policy_jobs.html.markdown | 18 + .../d/is_backup_policy_plan.html.markdown | 5 + website/docs/d/is_snapshot.html.markdown | 12 + ...s_snapshot_consistency_group.html.markdown | 90 ++ ..._snapshot_consistency_groups.html.markdown | 89 ++ website/docs/d/is_snapshots.html.markdown | 18 +- website/docs/r/is_backup_policy.html.markdown | 8 +- website/docs/r/is_snapshot.html.markdown | 12 + ...s_snapshot_consistency_group.html.markdown | 119 +++ 31 files changed, 3197 insertions(+), 67 deletions(-) create mode 100644 ibm/service/vpc/data_source_ibm_is_snapshot_consistency_group.go create mode 100644 ibm/service/vpc/data_source_ibm_is_snapshot_consistency_group_test.go create mode 100644 ibm/service/vpc/data_source_ibm_is_snapshot_consistency_groups.go create mode 100644 ibm/service/vpc/data_source_ibm_is_snapshot_consistency_groups_test.go create mode 100644 ibm/service/vpc/resource_ibm_is_snapshot_consistency_group.go create mode 100644 ibm/service/vpc/resource_ibm_is_snapshot_consistency_group_test.go create mode 100644 website/docs/d/is_snapshot_consistency_group.html.markdown create mode 100644 website/docs/d/is_snapshot_consistency_groups.html.markdown create mode 100644 website/docs/r/is_snapshot_consistency_group.html.markdown diff --git a/examples/ibm-is-ng/main.tf b/examples/ibm-is-ng/main.tf index a3e74809b9..896216cc78 100644 --- a/examples/ibm-is-ng/main.tf +++ b/examples/ibm-is-ng/main.tf @@ -1094,8 +1094,16 @@ data "ibm_is_volumes" "example" { ## Backup Policy resource "ibm_is_backup_policy" "is_backup_policy" { - match_user_tags = ["tag1"] - name = "my-backup-policy" + match_user_tags = ["tag1"] + name = "my-backup-policy" + match_resource_type = "volume" +} + +resource "ibm_is_backup_policy" "is_backup_policy" { + match_user_tags = ["tag1"] + name = "my-backup-policy-instance" + match_resource_type = "instance" + included_content = ["boot_volume", "data_volumes"] } resource "ibm_is_backup_policy_plan" "is_backup_policy_plan" { @@ -1399,3 +1407,30 @@ resource "ibm_is_image_deprecate" "example" { resource "ibm_is_image_obsolete" "example" { image = ibm_is_image.image1.id } + + +//snapshot consistency group + +resource "ibm_is_snapshot_consistency_group" "is_snapshot_consistency_group_instance" { + delete_snapshots_on_delete = true + snapshots { + name = "exmaple-snapshot" + source_volume = ibm_is_instance.instance.volume_attachments[0].volume_id + } + snapshots { + name = "example-snapshot-1" + source_volume = ibm_is_instance.instance.volume_attachments[1].volume_id + } + name = "example-snapshot-consistency-group" +} + +data "ibm_is_snapshot_consistency_group" "is_snapshot_consistency_group_instance" { + identifier = ibm_is_snapshot_consistency_group.is_snapshot_consistency_group_instance.id +} +data "ibm_is_snapshot_consistency_group" "is_snapshot_consistency_group_instance" { + name = "example-snapshot-consistency-group" +} +data "ibm_is_snapshot_consistency_groups" "is_snapshot_consistency_group_instance" { + depends_on = [ibm_is_snapshot_consistency_group.is_snapshot_consistency_group_instance] + name = "example-snapshot-consistency-group" +} \ No newline at end of file diff --git a/go.mod b/go.mod index d69e3df819..638e7af953 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/IBM/schematics-go-sdk v0.2.2 github.com/IBM/secrets-manager-go-sdk/v2 v2.0.2 github.com/IBM/vpc-beta-go-sdk v0.6.0 - github.com/IBM/vpc-go-sdk v0.43.0 + github.com/IBM/vpc-go-sdk v0.45.0 github.com/ScaleFT/sshkeys v0.0.0-20200327173127-6142f742bca5 github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 github.com/akamai/AkamaiOPEN-edgegrid-golang/v5 v5.0.0 @@ -241,4 +241,4 @@ exclude ( github.com/kubernetes-incubator/external-storage v0.20.4-openstorage-rc2 k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible k8s.io/client-go v12.0.0+incompatible -) +) \ No newline at end of file diff --git a/go.sum b/go.sum index 9ee7c97b82..dd2b86dde3 100644 --- a/go.sum +++ b/go.sum @@ -178,6 +178,8 @@ github.com/IBM/vpc-beta-go-sdk v0.6.0 h1:wfM3AcW3zOM3xsRtZ+EA6+sESlGUjQ6Yf4n5QQy github.com/IBM/vpc-beta-go-sdk v0.6.0/go.mod h1:fzHDAQIqH/5yJmYsKodKHLcqxMDT+yfH6vZjdiw8CQA= github.com/IBM/vpc-go-sdk v0.43.0 h1:uy/qWIqETCXraUG2cq5sjScr6pZ79ZteY1v5iLUVQ3Q= github.com/IBM/vpc-go-sdk v0.43.0/go.mod h1:kRz9tqPvpHoA/qGrC/qVjTbi4ICuTChpG76L89liGL4= +github.com/IBM/vpc-go-sdk v0.45.0 h1:RFbUZH5vBRGAEW5+jRzbDlxB+a+GvG9EBhyYO52Tvrs= +github.com/IBM/vpc-go-sdk v0.45.0/go.mod h1:4Hs5d/aClmsxAzwDQkwG+ri0vW2ykPJdpM6hDLRwKcA= github.com/Jeffail/gabs v1.1.1 h1:V0uzR08Hj22EX8+8QMhyI9sX2hwRu+/RJhJUmnwda/E= github.com/Jeffail/gabs v1.1.1/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= github.com/Logicalis/asn1 v0.0.0-20190312173541-d60463189a56 h1:vuquMR410psHNax14XKNWa0Ae/kYgWJcXi0IFuX60N0= @@ -1273,6 +1275,7 @@ github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAl github.com/onsi/gomega v1.18.0/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.20.0/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc= github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM= diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go index 48915f7c9d..0bf1e29b21 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -485,6 +485,8 @@ func Provider() *schema.Provider { "ibm_is_snapshot_clone": vpc.DataSourceSnapshotClone(), "ibm_is_snapshot_clones": vpc.DataSourceSnapshotClones(), "ibm_is_snapshot": vpc.DataSourceSnapshot(), + "ibm_is_snapshot_consistency_group": vpc.DataSourceIBMIsSnapshotConsistencyGroup(), + "ibm_is_snapshot_consistency_groups": vpc.DataSourceIBMIsSnapshotConsistencyGroups(), "ibm_is_snapshots": vpc.DataSourceSnapshots(), "ibm_is_share": vpc.DataSourceIbmIsShare(), "ibm_is_source_share": vpc.DataSourceIbmIsSourceShare(), @@ -1091,6 +1093,7 @@ func Provider() *schema.Provider { "ibm_is_subnet_routing_table_attachment": vpc.ResourceIBMISSubnetRoutingTableAttachment(), "ibm_is_ssh_key": vpc.ResourceIBMISSSHKey(), "ibm_is_snapshot": vpc.ResourceIBMSnapshot(), + "ibm_is_snapshot_consistency_group": vpc.ResourceIBMIsSnapshotConsistencyGroup(), "ibm_is_volume": vpc.ResourceIBMISVolume(), "ibm_is_vpn_gateway": vpc.ResourceIBMISVPNGateway(), "ibm_is_vpn_gateway_connection": vpc.ResourceIBMISVPNGatewayConnection(), @@ -1532,6 +1535,7 @@ func Validator() validate.ValidatorDict { "ibm_is_share_replica_operations": vpc.ResourceIbmIsShareReplicaOperationsValidator(), "ibm_is_share_mount_target": vpc.ResourceIBMIsShareMountTargetValidator(), "ibm_is_snapshot": vpc.ResourceIBMISSnapshotValidator(), + "ibm_is_snapshot_consistency_group": vpc.ResourceIBMIsSnapshotConsistencyGroupValidator(), "ibm_is_ssh_key": vpc.ResourceIBMISSHKeyValidator(), "ibm_is_subnet": vpc.ResourceIBMISSubnetValidator(), "ibm_is_subnet_reserved_ip": vpc.ResourceIBMISSubnetReservedIPValidator(), @@ -1664,14 +1668,15 @@ func Validator() validate.ValidatorDict { "ibm_project_environment": project.ResourceIbmProjectEnvironmentValidator(), }, DataSourceValidatorDictionary: map[string]*validate.ResourceValidator{ - "ibm_is_subnet": vpc.DataSourceIBMISSubnetValidator(), - "ibm_is_snapshot": vpc.DataSourceIBMISSnapshotValidator(), - "ibm_is_images": vpc.DataSourceIBMISImagesValidator(), - "ibm_dl_offering_speeds": directlink.DataSourceIBMDLOfferingSpeedsValidator(), - "ibm_dl_routers": directlink.DataSourceIBMDLRoutersValidator(), - "ibm_resource_instance": resourcecontroller.DataSourceIBMResourceInstanceValidator(), - "ibm_resource_key": resourcecontroller.DataSourceIBMResourceKeyValidator(), - "ibm_resource_group": resourcemanager.DataSourceIBMResourceGroupValidator(), + "ibm_is_subnet": vpc.DataSourceIBMISSubnetValidator(), + "ibm_is_snapshot_consistency_group": vpc.DataSourceIBMISSnapshotConsistencyGroupValidator(), + "ibm_is_snapshot": vpc.DataSourceIBMISSnapshotValidator(), + "ibm_is_images": vpc.DataSourceIBMISImagesValidator(), + "ibm_dl_offering_speeds": directlink.DataSourceIBMDLOfferingSpeedsValidator(), + "ibm_dl_routers": directlink.DataSourceIBMDLRoutersValidator(), + "ibm_resource_instance": resourcecontroller.DataSourceIBMResourceInstanceValidator(), + "ibm_resource_key": resourcecontroller.DataSourceIBMResourceKeyValidator(), + "ibm_resource_group": resourcemanager.DataSourceIBMResourceGroupValidator(), // bare_metal_server "ibm_is_bare_metal_server": vpc.DataSourceIBMIsBareMetalServerValidator(), diff --git a/ibm/service/vpc/data_source_ibm_is_backup_policies.go b/ibm/service/vpc/data_source_ibm_is_backup_policies.go index d9f03c7f53..9e223abac2 100644 --- a/ibm/service/vpc/data_source_ibm_is_backup_policies.go +++ b/ibm/service/vpc/data_source_ibm_is_backup_policies.go @@ -81,6 +81,17 @@ func DataSourceIBMIsBackupPolicies() *schema.Resource { Type: schema.TypeString, }, }, + "match_resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type this backup policy will apply to. Resources that have both a matching type and a matching user tag will be subject to the backup policy.", + }, + "included_content": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The included content for backups created using this policy", + Elem: &schema.Schema{Type: schema.TypeString}, + }, "match_user_tags": &schema.Schema{ Type: schema.TypeList, Computed: true, @@ -273,7 +284,10 @@ func dataSourceIBMIsBackupPoliciesRead(context context.Context, d *schema.Resour break } start = flex.GetNext(backupPolicyCollection.Next) - matchBackupPolicies = append(matchBackupPolicies, backupPolicyCollection.BackupPolicies...) + for _, backupPolicyInfo := range backupPolicyCollection.BackupPolicies { + backupPolicies := backupPolicyInfo.(*vpcv1.BackupPolicy) + matchBackupPolicies = append(matchBackupPolicies, *backupPolicies) + } if start == "" { break } @@ -326,12 +340,16 @@ func dataSourceBackupPolicyCollectionBackupPoliciesToMap(backupPoliciesItem vpcv if backupPoliciesItem.LastJobCompletedAt != nil { backupPoliciesMap["last_job_completed_at"] = flex.DateTimeToString(backupPoliciesItem.LastJobCompletedAt) } - if backupPoliciesItem.MatchResourceTypes != nil { - backupPoliciesMap["match_resource_types"] = backupPoliciesItem.MatchResourceTypes + if backupPoliciesItem.MatchResourceType != nil { + backupPoliciesMap["match_resource_types"] = []string{*backupPoliciesItem.MatchResourceType} + backupPoliciesMap["match_resource_type"] = *backupPoliciesItem.MatchResourceType } if backupPoliciesItem.MatchUserTags != nil { backupPoliciesMap["match_user_tags"] = backupPoliciesItem.MatchUserTags } + if backupPoliciesItem.IncludedContent != nil { + backupPoliciesMap["included_content"] = backupPoliciesItem.IncludedContent + } if backupPoliciesItem.Name != nil { backupPoliciesMap["name"] = backupPoliciesItem.Name } diff --git a/ibm/service/vpc/data_source_ibm_is_backup_policy.go b/ibm/service/vpc/data_source_ibm_is_backup_policy.go index 7baaafa6cb..62d152f0ce 100644 --- a/ibm/service/vpc/data_source_ibm_is_backup_policy.go +++ b/ibm/service/vpc/data_source_ibm_is_backup_policy.go @@ -69,6 +69,17 @@ func DataSourceIBMIsBackupPolicy() *schema.Resource { Type: schema.TypeString, }, }, + "match_resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type this backup policy will apply to. Resources that have both a matching type and a matching user tag will be subject to the backup policy.", + }, + "included_content": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The included content for backups created using this policy", + Elem: &schema.Schema{Type: schema.TypeString}, + }, "match_user_tags": &schema.Schema{ Type: schema.TypeList, Computed: true, @@ -223,7 +234,7 @@ func dataSourceIBMIsBackupPolicyRead(context context.Context, d *schema.Resource log.Printf("[DEBUG] GetBackupPolicyWithContext failed %s\n%s", err, response) return diag.FromErr(fmt.Errorf("[ERROR] GetBackupPolicyWithContext failed %s\n%s", err, response)) } - backupPolicy = backupPolicyInfo + backupPolicy = backupPolicyInfo.(*vpcv1.BackupPolicy) } else if v, ok := d.GetOk("name"); ok { @@ -244,7 +255,10 @@ func dataSourceIBMIsBackupPolicyRead(context context.Context, d *schema.Resource break } start = flex.GetNext(backupPolicyCollection.Next) - allrecs = append(allrecs, backupPolicyCollection.BackupPolicies...) + for _, backupPolicyInfo := range backupPolicyCollection.BackupPolicies { + backupPolicies := backupPolicyInfo.(*vpcv1.BackupPolicy) + allrecs = append(allrecs, *backupPolicies) + } if start == "" { break } @@ -316,13 +330,20 @@ func dataSourceIBMIsBackupPolicyRead(context context.Context, d *schema.Resource } } - matchResourceType := make([]string, 0) - if backupPolicy.MatchResourceTypes != nil { - for _, matchResourceTyp := range backupPolicy.MatchResourceTypes { - matchResourceType = append(matchResourceType, matchResourceTyp) + if backupPolicy.MatchResourceType != nil { + if err = d.Set("match_resource_types", []string{*backupPolicy.MatchResourceType}); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting match_resource_types: %s", err)) + } + if err = d.Set("match_resource_type", *backupPolicy.MatchResourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting match_resource_type: %s", err)) + } + } + + if backupPolicy.IncludedContent != nil { + if err = d.Set("included_content", backupPolicy.IncludedContent); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting included_content: %s", err)) } } - d.Set("match_resource_types", matchResourceType) matchUserTags := make([]string, 0) if backupPolicy.MatchUserTags != nil { diff --git a/ibm/service/vpc/data_source_ibm_is_backup_policy_job.go b/ibm/service/vpc/data_source_ibm_is_backup_policy_job.go index 6c63a9e255..a7aee98b28 100644 --- a/ibm/service/vpc/data_source_ibm_is_backup_policy_job.go +++ b/ibm/service/vpc/data_source_ibm_is_backup_policy_job.go @@ -7,6 +7,7 @@ import ( "context" "fmt" "log" + "reflect" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -75,6 +76,25 @@ func DataSourceIBMIsBackupPolicyJob() *schema.Resource { Computed: true, Description: "The unique user-defined name for this backup policy plan.", }, + "remote": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates that the resource associated with this reference is remote and therefore may not be directly retrievable.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this region.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this region.", + }, + }, + }, + }, "resource_type": &schema.Schema{ Type: schema.TypeString, Computed: true, @@ -109,6 +129,73 @@ func DataSourceIBMIsBackupPolicyJob() *schema.Resource { Description: "The resource type.", }, "source_volume": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The source volume this backup was created from (may be[deleted](https://cloud.ibm.com/apidocs/vpc#deleted-resources)).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this volume.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this volume.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this volume.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this volume.", + }, + "remote": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates that the resource associated with this reference is remote and therefore may not be directly retrievable.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this region.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this region.", + }, + }, + }, + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "source_instance": &schema.Schema{ Type: schema.TypeList, Computed: true, Description: "The source volume this backup was created from (may be[deleted](https://cloud.ibm.com/apidocs/vpc#deleted-resources)).", @@ -280,11 +367,25 @@ func dataSourceIBMIsBackupPolicyJobRead(context context.Context, d *schema.Resou } if backupPolicyJob.Source != nil { - jobSource := backupPolicyJob.Source.(*vpcv1.BackupPolicyJobSource) - err = d.Set("source_volume", dataSourceBackupPolicyJobFlattenSourceVolume(*jobSource)) - if err != nil { - return diag.FromErr(fmt.Errorf("Error setting source_volume %s", err)) + switch reflect.TypeOf(backupPolicyJob.Source).String() { + case "*vpcv1.BackupPolicyJobSourceVolumeReference": + { + jobSource := backupPolicyJob.Source.(*vpcv1.BackupPolicyJobSourceVolumeReference) + err = d.Set("source_volume", dataSourceBackupPolicyJobFlattenSourceVolume(*jobSource)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting source_volume %s", err)) + } + } + case "*vpcv1.BackupPolicyJobSourceInstanceReference": + { + jobSource := backupPolicyJob.Source.(*vpcv1.BackupPolicyJobSourceInstanceReference) + err = d.Set("source_instance", dataSourceBackupPolicyJobFlattenSourceInstance(*jobSource)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting source_instance %s", err)) + } + } } + } if err = d.Set("status", backupPolicyJob.Status); err != nil { return diag.FromErr(fmt.Errorf("Error setting status: %s", err)) @@ -333,10 +434,16 @@ func dataSourceBackupPolicyJobBackupPolicyPlanToMap(backupPolicyPlanItem vpcv1.B if backupPolicyPlanItem.Name != nil { backupPolicyPlanMap["name"] = backupPolicyPlanItem.Name } + if backupPolicyPlanItem.Remote != nil { + remoteMap, err := resourceIBMIsBackupPolicyPlanRemoteToMap(backupPolicyPlanItem.Remote) + if err != nil { + return remoteMap + } + backupPolicyPlanMap["remote"] = []map[string]interface{}{remoteMap} + } if backupPolicyPlanItem.ResourceType != nil { backupPolicyPlanMap["resource_type"] = backupPolicyPlanItem.ResourceType } - return backupPolicyPlanMap } @@ -350,7 +457,7 @@ func dataSourceBackupPolicyJobBackupPolicyPlanDeletedToMap(deletedItem vpcv1.Bac return deletedMap } -func dataSourceBackupPolicyJobFlattenSourceVolume(result vpcv1.BackupPolicyJobSource) (finalList []map[string]interface{}) { +func dataSourceBackupPolicyJobFlattenSourceVolume(result vpcv1.BackupPolicyJobSourceVolumeReference) (finalList []map[string]interface{}) { finalList = []map[string]interface{}{} finalMap := dataSourceBackupPolicyJobSourceVolumeToMap(result) finalList = append(finalList, finalMap) @@ -358,7 +465,7 @@ func dataSourceBackupPolicyJobFlattenSourceVolume(result vpcv1.BackupPolicyJobSo return finalList } -func dataSourceBackupPolicyJobSourceVolumeToMap(sourceVolumeItem vpcv1.BackupPolicyJobSource) (sourceVolumeMap map[string]interface{}) { +func dataSourceBackupPolicyJobSourceVolumeToMap(sourceVolumeItem vpcv1.BackupPolicyJobSourceVolumeReference) (sourceVolumeMap map[string]interface{}) { sourceVolumeMap = map[string]interface{}{} if sourceVolumeItem.CRN != nil { @@ -379,10 +486,57 @@ func dataSourceBackupPolicyJobSourceVolumeToMap(sourceVolumeItem vpcv1.BackupPol if sourceVolumeItem.Name != nil { sourceVolumeMap["name"] = sourceVolumeItem.Name } - + if sourceVolumeItem.ResourceType != nil { + sourceVolumeMap["resource_type"] = sourceVolumeItem.ResourceType + } + if sourceVolumeItem.Remote != nil { + remoteMap, err := resourceIBMIsSnapshotConsistencyGroupVolumeRemoteToMap(sourceVolumeItem.Remote) + if err != nil { + return remoteMap + } + sourceVolumeMap["remote"] = []map[string]interface{}{remoteMap} + } return sourceVolumeMap } +func resourceIBMIsSnapshotConsistencyGroupVolumeRemoteToMap(model *vpcv1.VolumeRemote) (map[string]interface{}, error) { + regionMap := make(map[string]interface{}) + if model.Region != nil { + regionMap, err := resourceIBMIsVolumeConsistencyGroupRegionReferenceToMap(model.Region) + if err != nil { + return regionMap, err + } + return regionMap, nil + } + return regionMap, nil +} + +func resourceIBMIsVolumeConsistencyGroupRegionReferenceToMap(model *vpcv1.RegionReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = model.Href + modelMap["name"] = model.Name + return modelMap, nil +} + +func resourceIBMIsBackupPolicyPlanRemoteToMap(model *vpcv1.BackupPolicyPlanRemote) (map[string]interface{}, error) { + regionMap := make(map[string]interface{}) + if model.Region != nil { + regionMap, err := resourceIBMIsBackupPolicyPlanRemoteRegionReferenceToMap(model.Region) + if err != nil { + return regionMap, err + } + return regionMap, nil + } + return regionMap, nil +} + +func resourceIBMIsBackupPolicyPlanRemoteRegionReferenceToMap(model *vpcv1.RegionReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = model.Href + modelMap["name"] = model.Name + return modelMap, nil +} + func dataSourceBackupPolicyJobSourceVolumeDeletedToMap(deletedItem vpcv1.VolumeReferenceDeleted) (deletedMap map[string]interface{}) { deletedMap = map[string]interface{}{} @@ -392,6 +546,47 @@ func dataSourceBackupPolicyJobSourceVolumeDeletedToMap(deletedItem vpcv1.VolumeR return deletedMap } +func dataSourceBackupPolicyJobFlattenSourceInstance(result vpcv1.BackupPolicyJobSourceInstanceReference) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceBackupPolicyJobSourceInstanceToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceBackupPolicyJobSourceInstanceToMap(sourceVolumeItem vpcv1.BackupPolicyJobSourceInstanceReference) (sourceVolumeMap map[string]interface{}) { + sourceVolumeMap = map[string]interface{}{} + + if sourceVolumeItem.CRN != nil { + sourceVolumeMap["crn"] = sourceVolumeItem.CRN + } + if sourceVolumeItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceBackupPolicyJobSourceInstanceDeletedToMap(*sourceVolumeItem.Deleted) + deletedList = append(deletedList, deletedMap) + sourceVolumeMap["deleted"] = deletedList + } + if sourceVolumeItem.Href != nil { + sourceVolumeMap["href"] = sourceVolumeItem.Href + } + if sourceVolumeItem.ID != nil { + sourceVolumeMap["id"] = sourceVolumeItem.ID + } + if sourceVolumeItem.Name != nil { + sourceVolumeMap["name"] = sourceVolumeItem.Name + } + return sourceVolumeMap +} + +func dataSourceBackupPolicyJobSourceInstanceDeletedToMap(deletedItem vpcv1.InstanceReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} func dataSourceBackupPolicyJobFlattenStatusReasons(result []vpcv1.BackupPolicyJobStatusReason) (statusReasons []map[string]interface{}) { for _, statusReasonsItem := range result { diff --git a/ibm/service/vpc/data_source_ibm_is_backup_policy_jobs.go b/ibm/service/vpc/data_source_ibm_is_backup_policy_jobs.go index c592018f46..0377373cd2 100644 --- a/ibm/service/vpc/data_source_ibm_is_backup_policy_jobs.go +++ b/ibm/service/vpc/data_source_ibm_is_backup_policy_jobs.go @@ -7,6 +7,7 @@ import ( "context" "fmt" "log" + "reflect" "strings" "time" @@ -109,6 +110,25 @@ func DataSourceIBMIsBackupPolicyJobs() *schema.Resource { Computed: true, Description: "The unique user-defined name for this backup policy plan.", }, + "remote": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates that the resource associated with this reference is remote and therefore may not be directly retrievable.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this region.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this region.", + }, + }, + }, + }, "resource_type": &schema.Schema{ Type: schema.TypeString, Computed: true, @@ -148,6 +168,73 @@ func DataSourceIBMIsBackupPolicyJobs() *schema.Resource { Description: "The resource type.", }, "source_volume": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The source volume this backup was created from (may be[deleted](https://cloud.ibm.com/apidocs/vpc#deleted-resources)).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this volume.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this volume.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this volume.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique user-defined name for this volume.", + }, + "remote": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates that the resource associated with this reference is remote and therefore may not be directly retrievable.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this region.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this region.", + }, + }, + }, + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "source_instance": &schema.Schema{ Type: schema.TypeList, Computed: true, Description: "The source volume this backup was created from (may be[deleted](https://cloud.ibm.com/apidocs/vpc#deleted-resources)).", @@ -408,11 +495,24 @@ func dataSourceBackupPolicyJobCollectionJobsToMap(jobsItem vpcv1.BackupPolicyJob log.Println("jobsItem.Source") log.Println(jobsItem.Source) if jobsItem.Source != nil { - sourceVolumeList := []map[string]interface{}{} - jobSource := jobsItem.Source.(*vpcv1.BackupPolicyJobSource) - sourceVolumeMap := dataSourceBackupPolicyJobCollectionJobsSourceVolumeToMap(*jobSource) - sourceVolumeList = append(sourceVolumeList, sourceVolumeMap) - jobsMap["source_volume"] = sourceVolumeList + switch reflect.TypeOf(jobsItem.Source).String() { + case "*vpcv1.BackupPolicyJobSourceVolumeReference": + { + jobSource := jobsItem.Source.(*vpcv1.BackupPolicyJobSourceVolumeReference) + sourceVolumeList := []map[string]interface{}{} + sourceVolumeMap := dataSourceBackupPolicyJobCollectionJobsSourceVolumeToMap(*jobSource) + sourceVolumeList = append(sourceVolumeList, sourceVolumeMap) + jobsMap["source_volume"] = sourceVolumeList + } + case "*vpcv1.BackupPolicyJobSourceInstanceReference": + { + jobSource := jobsItem.Source.(*vpcv1.BackupPolicyJobSourceInstanceReference) + sourceVolumeList := []map[string]interface{}{} + sourceVolumeMap := dataSourceBackupPolicyJobCollectionJobsSourceInstanceToMap(*jobSource) + sourceVolumeList = append(sourceVolumeList, sourceVolumeMap) + jobsMap["source_instance"] = sourceVolumeList + } + } } if jobsItem.Status != nil { jobsMap["status"] = jobsItem.Status @@ -457,6 +557,13 @@ func dataSourceBackupPolicyJobCollectionJobsBackupPolicyPlanToMap(backupPolicyPl if backupPolicyPlanItem.Name != nil { backupPolicyPlanMap["name"] = backupPolicyPlanItem.Name } + if backupPolicyPlanItem.Remote != nil { + remoteMap, err := resourceIBMIsSnapshotConsistencyGroupBackupPolicyPlanRemoteToMap(backupPolicyPlanItem.Remote) + if err != nil { + return remoteMap + } + backupPolicyPlanMap["remote"] = []map[string]interface{}{remoteMap} + } if backupPolicyPlanItem.ResourceType != nil { backupPolicyPlanMap["resource_type"] = backupPolicyPlanItem.ResourceType } @@ -474,7 +581,7 @@ func dataSourceBackupPolicyJobCollectionBackupPolicyPlanDeletedToMap(deletedItem return deletedMap } -func dataSourceBackupPolicyJobCollectionJobsSourceVolumeToMap(sourceVolumeItem vpcv1.BackupPolicyJobSource) (sourceVolumeMap map[string]interface{}) { +func dataSourceBackupPolicyJobCollectionJobsSourceVolumeToMap(sourceVolumeItem vpcv1.BackupPolicyJobSourceVolumeReference) (sourceVolumeMap map[string]interface{}) { sourceVolumeMap = map[string]interface{}{} if sourceVolumeItem.CRN != nil { @@ -495,7 +602,40 @@ func dataSourceBackupPolicyJobCollectionJobsSourceVolumeToMap(sourceVolumeItem v if sourceVolumeItem.Name != nil { sourceVolumeMap["name"] = sourceVolumeItem.Name } + if sourceVolumeItem.Remote != nil { + remoteMap, err := resourceIBMIsSnapshotConsistencyGroupVolumeRemoteToMap(sourceVolumeItem.Remote) + if err != nil { + return remoteMap + } + sourceVolumeMap["remote"] = []map[string]interface{}{remoteMap} + } + if sourceVolumeItem.ResourceType != nil { + sourceVolumeMap["resource_type"] = sourceVolumeItem.ResourceType + } + return sourceVolumeMap +} + +func dataSourceBackupPolicyJobCollectionJobsSourceInstanceToMap(sourceVolumeItem vpcv1.BackupPolicyJobSourceInstanceReference) (sourceVolumeMap map[string]interface{}) { + sourceVolumeMap = map[string]interface{}{} + if sourceVolumeItem.CRN != nil { + sourceVolumeMap["crn"] = sourceVolumeItem.CRN + } + if sourceVolumeItem.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceBackupPolicyJobCollectionSourceInstanceDeletedToMap(*sourceVolumeItem.Deleted) + deletedList = append(deletedList, deletedMap) + sourceVolumeMap["deleted"] = deletedList + } + if sourceVolumeItem.Href != nil { + sourceVolumeMap["href"] = sourceVolumeItem.Href + } + if sourceVolumeItem.ID != nil { + sourceVolumeMap["id"] = sourceVolumeItem.ID + } + if sourceVolumeItem.Name != nil { + sourceVolumeMap["name"] = sourceVolumeItem.Name + } return sourceVolumeMap } @@ -508,6 +648,15 @@ func dataSourceBackupPolicyJobCollectionSourceVolumeDeletedToMap(deletedItem vpc return deletedMap } +func dataSourceBackupPolicyJobCollectionSourceInstanceDeletedToMap(deletedItem vpcv1.InstanceReferenceDeleted) (deletedMap map[string]interface{}) { + deletedMap = map[string]interface{}{} + + if deletedItem.MoreInfo != nil { + deletedMap["more_info"] = deletedItem.MoreInfo + } + + return deletedMap +} func dataSourceBackupPolicyJobCollectionJobsStatusReasonsToMap(statusReasonsItem vpcv1.BackupPolicyJobStatusReason) (statusReasonsMap map[string]interface{}) { statusReasonsMap = map[string]interface{}{} diff --git a/ibm/service/vpc/data_source_ibm_is_snapshot.go b/ibm/service/vpc/data_source_ibm_is_snapshot.go index 9a174c4c02..26c94fb09e 100644 --- a/ibm/service/vpc/data_source_ibm_is_snapshot.go +++ b/ibm/service/vpc/data_source_ibm_is_snapshot.go @@ -182,6 +182,54 @@ func DataSourceSnapshot() *schema.Resource { }, }, }, + isSnapshotConsistencyGroup: { + Type: schema.TypeList, + Computed: true, + Description: "The snapshot consistency group which created this snapshot.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN of this snapshot consistency group.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted, and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for the snapshot consistency group.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for the snapshot consistency group.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for the snapshot consistency group. The name is unique across all snapshot consistency groups in the region.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, isSnapshotSourceImage: { Type: schema.TypeString, Computed: true, @@ -406,6 +454,24 @@ func snapshotGetByNameOrID(d *schema.ResourceData, meta interface{}, name, id st } d.Set(isSnapshotSourceSnapshot, sourceSnapshotList) + // snapshot consistency group + snapshotConsistencyGroupList := []map[string]interface{}{} + if snapshot.SnapshotConsistencyGroup != nil { + snapshotConsistencyGroup := map[string]interface{}{} + snapshotConsistencyGroup["href"] = snapshot.SnapshotConsistencyGroup.Href + snapshotConsistencyGroup["crn"] = snapshot.SnapshotConsistencyGroup.CRN + if snapshot.SnapshotConsistencyGroup.Deleted != nil { + snapshotConsistencyGroupDeletedMap := map[string]interface{}{} + snapshotConsistencyGroupDeletedMap["more_info"] = snapshot.SnapshotConsistencyGroup.Deleted.MoreInfo + snapshotConsistencyGroup["deleted"] = []map[string]interface{}{snapshotConsistencyGroupDeletedMap} + } + snapshotConsistencyGroup["id"] = snapshot.SnapshotConsistencyGroup.ID + snapshotConsistencyGroup["name"] = snapshot.SnapshotConsistencyGroup.Name + snapshotConsistencyGroup["resource_type"] = snapshot.SnapshotConsistencyGroup.ResourceType + snapshotConsistencyGroupList = append(snapshotConsistencyGroupList, snapshotConsistencyGroup) + } + d.Set(isSnapshotConsistencyGroup, snapshotConsistencyGroupList) + // snapshot copies snapshotCopies := []map[string]interface{}{} if snapshot.Copies != nil { diff --git a/ibm/service/vpc/data_source_ibm_is_snapshot_consistency_group.go b/ibm/service/vpc/data_source_ibm_is_snapshot_consistency_group.go new file mode 100644 index 0000000000..74a7efa3c0 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_snapshot_consistency_group.go @@ -0,0 +1,589 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsSnapshotConsistencyGroup() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsSnapshotConsistencyGroupRead, + + Schema: map[string]*schema.Schema{ + "identifier": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"name", "identifier"}, + ValidateFunc: validate.InvokeDataSourceValidator("ibm_is_snapshot_consistency_group", "identifier"), + Description: "The snapshot consistency group identifier.", + }, + "name": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"name", "identifier"}, + ValidateFunc: validate.InvokeDataSourceValidator("ibm_is_snapshot_consistency_group", isSnapshotName), + Description: "The name for this snapshot consistency group. The name is unique across all snapshot consistency groups in the region.", + }, + "backup_policy_plan": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, the backup policy plan which created this snapshot consistency group.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted, and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this backup policy plan.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this backup policy plan.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this backup policy plan. The name is unique across all plans in the backup policy.", + }, + "remote": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource is remote to this region,and identifies the native region.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this region.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this region.", + }, + }, + }, + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this snapshot consistency group was created.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN of this snapshot consistency group.", + }, + "delete_snapshots_on_delete": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether deleting the snapshot consistency group will also delete the snapshots in the group.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this snapshot consistency group.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of this snapshot consistency group.", + }, + "resource_group": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The resource group for this snapshot consistency group.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this resource group.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this resource group.", + }, + }, + }, + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "service_tags": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The [service tags](https://cloud.ibm.com/apidocs/tagging#types-of-tags)[`is.instance:` prefix](https://cloud.ibm.com/docs/vpc?topic=vpc-snapshots-vpc-faqs) associated with this snapshot consistency group.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "snapshots": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The member snapshots that are data-consistent with respect to captured time. (may be[deleted](https://cloud.ibm.com/apidocs/vpc#deleted-resources)).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN of this snapshot.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted, and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this snapshot.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this snapshot.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this snapshot. The name is unique across all snapshots in the region.", + }, + "remote": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource is remote to this region,and identifies the native region.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this region.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this region.", + }, + }, + }, + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "tags": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_snapshot_consistency_group", "tags")}, + Set: flex.ResourceIBMVPCHash, + Description: "Snapshot Consistency Group tags list", + }, + "access_tags": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_snapshot_consistency_group", "access_tags")}, + Set: flex.ResourceIBMVPCHash, + Description: "List of access management tags", + }, + }, + } +} + +func DataSourceIBMISSnapshotConsistencyGroupValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "identifier", + ValidateFunctionIdentifier: validate.ValidateNoZeroValues, + Type: validate.TypeString}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isSnapshotName, + ValidateFunctionIdentifier: validate.ValidateNoZeroValues, + Type: validate.TypeString}) + + ibmISSnapshotDataSourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_snapshot_consistency_group", Schema: validateSchema} + return &ibmISSnapshotDataSourceValidator +} + +func dataSourceIBMIsSnapshotConsistencyGroupRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + name := d.Get("name").(string) + id := d.Get("identifier").(string) + + if name != "" { + start := "" + allrecs := []vpcv1.SnapshotConsistencyGroup{} + for { + listSnapshotConsistencyGroupsOptions := &vpcv1.ListSnapshotConsistencyGroupsOptions{} + if start != "" { + listSnapshotConsistencyGroupsOptions.Start = &start + } + if rgFilterOk, ok := d.GetOk("resource_group"); ok { + rgFilter := rgFilterOk.(string) + listSnapshotConsistencyGroupsOptions.ResourceGroupID = &rgFilter + } + if nameFilterOk, ok := d.GetOk("name"); ok { + nameFilter := nameFilterOk.(string) + listSnapshotConsistencyGroupsOptions.Name = &nameFilter + } + if backupPolicyPlanIdFilterOk, ok := d.GetOk("backup_policy_plan"); ok { + backupPolicyPlanIdFilter := backupPolicyPlanIdFilterOk.(string) + listSnapshotConsistencyGroupsOptions.BackupPolicyPlanID = &backupPolicyPlanIdFilter + } + + snapshotConsistencyGroup, response, err := vpcClient.ListSnapshotConsistencyGroups(listSnapshotConsistencyGroupsOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error fetching snapshots %s\n%s", err, response)) + } + start = flex.GetNext(snapshotConsistencyGroup.Next) + allrecs = append(allrecs, snapshotConsistencyGroup.SnapshotConsistencyGroups...) + if start == "" { + break + } + } + for _, snapshotConsistencyGroup := range allrecs { + if *snapshotConsistencyGroup.Name == name || *snapshotConsistencyGroup.ID == id { + + d.SetId(fmt.Sprintf("%s", *snapshotConsistencyGroup.ID)) + + backupPolicyPlan := []map[string]interface{}{} + if snapshotConsistencyGroup.BackupPolicyPlan != nil { + modelMap, err := dataSourceIBMIsSnapshotConsistencyGroupBackupPolicyPlanReferenceToMap(snapshotConsistencyGroup.BackupPolicyPlan) + if err != nil { + return diag.FromErr(err) + } + backupPolicyPlan = append(backupPolicyPlan, modelMap) + } + if err = d.Set("backup_policy_plan", backupPolicyPlan); err != nil { + return diag.FromErr(fmt.Errorf("Error setting backup_policy_plan %s", err)) + } + + if err = d.Set("created_at", flex.DateTimeToString(snapshotConsistencyGroup.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + + if err = d.Set("crn", snapshotConsistencyGroup.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("delete_snapshots_on_delete", snapshotConsistencyGroup.DeleteSnapshotsOnDelete); err != nil { + return diag.FromErr(fmt.Errorf("Error setting delete_snapshots_on_delete: %s", err)) + } + + if err = d.Set("href", snapshotConsistencyGroup.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + if err = d.Set("lifecycle_state", snapshotConsistencyGroup.LifecycleState); err != nil { + return diag.FromErr(fmt.Errorf("Error setting lifecycle_state: %s", err)) + } + + if err = d.Set("name", snapshotConsistencyGroup.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + resourceGroup := []map[string]interface{}{} + if snapshotConsistencyGroup.ResourceGroup != nil { + modelMap, err := dataSourceIBMIsSnapshotConsistencyGroupResourceGroupReferenceToMap(snapshotConsistencyGroup.ResourceGroup) + if err != nil { + return diag.FromErr(err) + } + resourceGroup = append(resourceGroup, modelMap) + } + if err = d.Set("resource_group", resourceGroup); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group %s", err)) + } + + if err = d.Set("resource_type", snapshotConsistencyGroup.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_type: %s", err)) + } + + snapshots := []map[string]interface{}{} + if snapshotConsistencyGroup.Snapshots != nil { + for _, modelItem := range snapshotConsistencyGroup.Snapshots { + modelMap, err := dataSourceIBMIsSnapshotConsistencyGroupSnapshotConsistencyGroupSnapshotsItemToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + snapshots = append(snapshots, modelMap) + } + } + if err = d.Set("snapshots", snapshots); err != nil { + return diag.FromErr(fmt.Errorf("Error setting snapshots %s", err)) + } + tags, err := flex.GetGlobalTagsUsingCRN(meta, *snapshotConsistencyGroup.CRN, "", isUserTagType) + if err != nil { + log.Printf( + "Error on get of resource vpc snapshot consistency group (%s) tags: %s", d.Id(), err) + } + d.Set("tags", tags) + + accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *snapshotConsistencyGroup.CRN, "", isAccessTagType) + if err != nil { + log.Printf( + "Error on get of resource VPC snapshot consistency group (%s) access tags: %s", d.Id(), err) + } + d.Set("access_tags", accesstags) + return nil + } + } + return diag.FromErr(fmt.Errorf("[ERROR] No snapshot consistency group found with name %s", name)) + } else { + getSnapshotConsistencyGroupOptions := &vpcv1.GetSnapshotConsistencyGroupOptions{} + + getSnapshotConsistencyGroupOptions.SetID(id) + + snapshotConsistencyGroup, response, err := vpcClient.GetSnapshotConsistencyGroupWithContext(context, getSnapshotConsistencyGroupOptions) + if err != nil { + log.Printf("[DEBUG] GetSnapshotConsistencyGroupWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetSnapshotConsistencyGroupWithContext failed %s\n%s", err, response)) + } + + d.SetId(fmt.Sprintf("%s", *getSnapshotConsistencyGroupOptions.ID)) + + backupPolicyPlan := []map[string]interface{}{} + if snapshotConsistencyGroup.BackupPolicyPlan != nil { + modelMap, err := dataSourceIBMIsSnapshotConsistencyGroupBackupPolicyPlanReferenceToMap(snapshotConsistencyGroup.BackupPolicyPlan) + if err != nil { + return diag.FromErr(err) + } + backupPolicyPlan = append(backupPolicyPlan, modelMap) + } + if err = d.Set("backup_policy_plan", backupPolicyPlan); err != nil { + return diag.FromErr(fmt.Errorf("Error setting backup_policy_plan %s", err)) + } + + if err = d.Set("created_at", flex.DateTimeToString(snapshotConsistencyGroup.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + + if err = d.Set("crn", snapshotConsistencyGroup.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + + if err = d.Set("delete_snapshots_on_delete", snapshotConsistencyGroup.DeleteSnapshotsOnDelete); err != nil { + return diag.FromErr(fmt.Errorf("Error setting delete_snapshots_on_delete: %s", err)) + } + + if err = d.Set("href", snapshotConsistencyGroup.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + + if err = d.Set("lifecycle_state", snapshotConsistencyGroup.LifecycleState); err != nil { + return diag.FromErr(fmt.Errorf("Error setting lifecycle_state: %s", err)) + } + + if err = d.Set("name", snapshotConsistencyGroup.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + + resourceGroup := []map[string]interface{}{} + if snapshotConsistencyGroup.ResourceGroup != nil { + modelMap, err := dataSourceIBMIsSnapshotConsistencyGroupResourceGroupReferenceToMap(snapshotConsistencyGroup.ResourceGroup) + if err != nil { + return diag.FromErr(err) + } + resourceGroup = append(resourceGroup, modelMap) + } + if err = d.Set("resource_group", resourceGroup); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_group %s", err)) + } + + if err = d.Set("resource_type", snapshotConsistencyGroup.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_type: %s", err)) + } + + snapshots := []map[string]interface{}{} + if snapshotConsistencyGroup.Snapshots != nil { + for _, modelItem := range snapshotConsistencyGroup.Snapshots { + modelMap, err := dataSourceIBMIsSnapshotConsistencyGroupSnapshotConsistencyGroupSnapshotsItemToMap(&modelItem) + if err != nil { + return diag.FromErr(err) + } + snapshots = append(snapshots, modelMap) + } + } + if err = d.Set("snapshots", snapshots); err != nil { + return diag.FromErr(fmt.Errorf("Error setting snapshots %s", err)) + } + tags, err := flex.GetGlobalTagsUsingCRN(meta, *snapshotConsistencyGroup.CRN, "", isUserTagType) + if err != nil { + log.Printf( + "Error on get of resource vpc snapshot consistency group (%s) tags: %s", d.Id(), err) + } + d.Set("tags", tags) + + accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *snapshotConsistencyGroup.CRN, "", isAccessTagType) + if err != nil { + log.Printf( + "Error on get of resource VPC snapshot consistency group (%s) access tags: %s", d.Id(), err) + } + d.Set("access_tags", accesstags) + return nil + } + +} + +func dataSourceIBMIsSnapshotConsistencyGroupBackupPolicyPlanReferenceToMap(model *vpcv1.BackupPolicyPlanReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsSnapshotConsistencyGroupBackupPolicyPlanReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap["deleted"] = []map[string]interface{}{deletedMap} + } + modelMap["href"] = model.Href + modelMap["id"] = model.ID + modelMap["name"] = model.Name + if model.Remote != nil { + remoteMap, err := dataSourceIBMIsSnapshotConsistencyGroupBackupPolicyPlanRemoteToMap(model.Remote) + if err != nil { + return modelMap, err + } + modelMap["remote"] = []map[string]interface{}{remoteMap} + } + modelMap["resource_type"] = model.ResourceType + return modelMap, nil +} + +func dataSourceIBMIsSnapshotConsistencyGroupBackupPolicyPlanReferenceDeletedToMap(model *vpcv1.BackupPolicyPlanReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func dataSourceIBMIsSnapshotConsistencyGroupBackupPolicyPlanRemoteToMap(model *vpcv1.BackupPolicyPlanRemote) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Region != nil { + regionMap, err := dataSourceIBMIsSnapshotConsistencyGroupRegionReferenceToMap(model.Region) + if err != nil { + return modelMap, err + } + return regionMap, nil + } + return modelMap, nil +} + +func dataSourceIBMIsSnapshotConsistencyGroupRegionReferenceToMap(model *vpcv1.RegionReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = model.Href + modelMap["name"] = model.Name + return modelMap, nil +} + +func dataSourceIBMIsSnapshotConsistencyGroupResourceGroupReferenceToMap(model *vpcv1.ResourceGroupReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = model.Href + modelMap["id"] = model.ID + modelMap["name"] = model.Name + return modelMap, nil +} + +func dataSourceIBMIsSnapshotConsistencyGroupSnapshotConsistencyGroupSnapshotsItemToMap(model *vpcv1.SnapshotConsistencyGroupSnapshotsItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + if model.Deleted != nil { + deletedMap, err := dataSourceIBMIsSnapshotConsistencyGroupSnapshotReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap["deleted"] = []map[string]interface{}{deletedMap} + } + modelMap["href"] = model.Href + modelMap["id"] = model.ID + modelMap["name"] = model.Name + if model.Remote != nil { + remoteMap, err := dataSourceIBMIsSnapshotConsistencyGroupSnapshotRemoteToMap(model.Remote) + if err != nil { + return modelMap, err + } + modelMap["remote"] = []map[string]interface{}{remoteMap} + } + modelMap["resource_type"] = model.ResourceType + return modelMap, nil +} + +func dataSourceIBMIsSnapshotConsistencyGroupSnapshotReferenceDeletedToMap(model *vpcv1.SnapshotReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func dataSourceIBMIsSnapshotConsistencyGroupSnapshotRemoteToMap(model *vpcv1.SnapshotRemote) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Region != nil { + log.Println("model.Region") + log.Println(model.Region) + regionMap, err := dataSourceIBMIsSnapshotConsistencyGroupRegionReferenceToMap(model.Region) + if err != nil { + return modelMap, err + } + return regionMap, nil + + } + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_snapshot_consistency_group_test.go b/ibm/service/vpc/data_source_ibm_is_snapshot_consistency_group_test.go new file mode 100644 index 0000000000..37a2c4c9b0 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_snapshot_consistency_group_test.go @@ -0,0 +1,61 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMIsSnapshotConsistencyGroupDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instance-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + deleteSnapshotsOnDelete := "true" + scgname := fmt.Sprintf("tf-snap-cons-grp-name-%d", acctest.RandIntRange(10, 100)) + snapname := fmt.Sprintf("tf-snap-name-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsSnapshotConsistencyGroupDataSourceConfigBasic(vpcname, subnetname, sshname, publicKey, name, scgname, snapname, deleteSnapshotsOnDelete), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "delete_snapshots_on_delete"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "resource_group.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "snapshots.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "snapshots.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "snapshots.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "snapshots.0.crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "snapshots.0.href"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsSnapshotConsistencyGroupDataSourceConfigBasic(vpcname, subnetname, sshname, publicKey, name, snapname, scgname, deleteSnapshotsOnDelete string) string { + return testAccCheckIBMIsSnapshotConsistencyGroupConfig(vpcname, subnetname, sshname, publicKey, name, scgname, snapname, deleteSnapshotsOnDelete) + fmt.Sprintf(` + data "ibm_is_snapshot_consistency_group" "is_snapshot_consistency_group" { + identifier = ibm_is_snapshot_consistency_group.is_snapshot_consistency_group.id + } +`) +} diff --git a/ibm/service/vpc/data_source_ibm_is_snapshot_consistency_groups.go b/ibm/service/vpc/data_source_ibm_is_snapshot_consistency_groups.go new file mode 100644 index 0000000000..50a22ea1e2 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_snapshot_consistency_groups.go @@ -0,0 +1,369 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsSnapshotConsistencyGroups() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsSnapshotConsistencyGroupsRead, + + Schema: map[string]*schema.Schema{ + "resource_group": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Filters the collection to resources with a `resource_group.id` property matching the specified identifier.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Filters the collection to resources with a `name` property matching the exact specified name.", + }, + "backup_policy_plan": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Filters the collection to backup policy jobs with a `backup_policy_plan.id` property matching the specified identifier.", + }, + "snapshot_consistency_groups": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Collection of snapshot consistency groups.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "backup_policy_plan": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, the backup policy plan which created this snapshot consistency group.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted, and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this backup policy plan.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this backup policy plan.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this backup policy plan. The name is unique across all plans in the backup policy.", + }, + "remote": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource is remote to this region,and identifies the native region.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this region.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this region.", + }, + }, + }, + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this snapshot consistency group was created.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN of this snapshot consistency group.", + }, + "delete_snapshots_on_delete": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether deleting the snapshot consistency group will also delete the snapshots in the group.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this snapshot consistency group.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this snapshot consistency group.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of this snapshot consistency group.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this snapshot consistency group. The name is unique across all snapshot consistency groups in the region.", + }, + "resource_group": { + Type: schema.TypeString, + Computed: true, + Description: "Resource group info", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "service_tags": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The [service tags](https://cloud.ibm.com/apidocs/tagging#types-of-tags)[`is.instance:` prefix](https://cloud.ibm.com/docs/vpc?topic=vpc-snapshots-vpc-faqs) associated with this snapshot consistency group.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "snapshots": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The member snapshots that are data-consistent with respect to captured time. (may be[deleted](https://cloud.ibm.com/apidocs/vpc#deleted-resources)).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN of this snapshot.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted, and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this snapshot.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this snapshot.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this snapshot. The name is unique across all snapshots in the region.", + }, + "remote": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource is remote to this region,and identifies the native region.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this region.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this region.", + }, + }, + }, + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + + "tags": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "User Tags for the snapshot consistency group", + }, + + "access_tags": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: flex.ResourceIBMVPCHash, + Description: "List of access tags", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsSnapshotConsistencyGroupsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + start := "" + allrecs := []vpcv1.SnapshotConsistencyGroup{} + for { + listSnapshotConsistencyGroupsOptions := &vpcv1.ListSnapshotConsistencyGroupsOptions{} + if start != "" { + listSnapshotConsistencyGroupsOptions.Start = &start + } + if rgFilterOk, ok := d.GetOk("resource_group"); ok { + rgFilter := rgFilterOk.(string) + listSnapshotConsistencyGroupsOptions.ResourceGroupID = &rgFilter + } + if nameFilterOk, ok := d.GetOk("name"); ok { + nameFilter := nameFilterOk.(string) + listSnapshotConsistencyGroupsOptions.Name = &nameFilter + } + if backupPolicyPlanIdFilterOk, ok := d.GetOk("backup_policy_plan"); ok { + backupPolicyPlanIdFilter := backupPolicyPlanIdFilterOk.(string) + listSnapshotConsistencyGroupsOptions.BackupPolicyPlanID = &backupPolicyPlanIdFilter + } + + snapshotConsistencyGroup, response, err := vpcClient.ListSnapshotConsistencyGroups(listSnapshotConsistencyGroupsOptions) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error fetching snapshots %s\n%s", err, response)) + } + start = flex.GetNext(snapshotConsistencyGroup.Next) + allrecs = append(allrecs, snapshotConsistencyGroup.SnapshotConsistencyGroups...) + if start == "" { + break + } + } + + snapshotConsistencyGroupsInfo := make([]map[string]interface{}, 0) + for _, snapshotConsistencyGroup := range allrecs { + l := map[string]interface{}{ + "id": *snapshotConsistencyGroup.ID, + "name": *snapshotConsistencyGroup.Name, + "href": *snapshotConsistencyGroup.Href, + "crn": *snapshotConsistencyGroup.CRN, + "delete_snapshots_on_delete": *snapshotConsistencyGroup.DeleteSnapshotsOnDelete, + "lifecycle_state": *snapshotConsistencyGroup.LifecycleState, + "resource_type": *snapshotConsistencyGroup.ResourceType, + "created_at": (*snapshotConsistencyGroup.CreatedAt).String(), + } + + //backup policy plan + backupPolicyPlanList := []map[string]interface{}{} + if snapshotConsistencyGroup.BackupPolicyPlan != nil { + backupPolicyPlan := map[string]interface{}{} + if snapshotConsistencyGroup.BackupPolicyPlan.Deleted != nil { + snapshotConsistencyGroupBackupPolicyPlanDeletedMap := map[string]interface{}{} + snapshotConsistencyGroupBackupPolicyPlanDeletedMap["more_info"] = snapshotConsistencyGroup.BackupPolicyPlan.Deleted.MoreInfo + backupPolicyPlan["deleted"] = []map[string]interface{}{snapshotConsistencyGroupBackupPolicyPlanDeletedMap} + } + backupPolicyPlan["href"] = snapshotConsistencyGroup.BackupPolicyPlan.Href + backupPolicyPlan["id"] = snapshotConsistencyGroup.BackupPolicyPlan.ID + backupPolicyPlan["name"] = snapshotConsistencyGroup.BackupPolicyPlan.Name + backupPolicyPlan["resource_type"] = snapshotConsistencyGroup.BackupPolicyPlan.ResourceType + backupPolicyPlanList = append(backupPolicyPlanList, backupPolicyPlan) + } + l[isSnapshotBackupPolicyPlan] = backupPolicyPlanList + + // source snapshot + if !core.IsNil(snapshotConsistencyGroup.Snapshots) { + snapshots := []map[string]interface{}{} + for _, snapshotsItem := range snapshotConsistencyGroup.Snapshots { + snapshotsItemMap, err := resourceIBMIsSnapshotConsistencyGroupSnapshotConsistencyGroupSnapshotsItemToMap(&snapshotsItem) + if err != nil { + return diag.FromErr(err) + } + snapshots = append(snapshots, snapshotsItemMap) + } + l["snapshots"] = snapshots + } else { + l["snapshots"] = []map[string]interface{}{} + } + + if snapshotConsistencyGroup.ResourceGroup != nil && snapshotConsistencyGroup.ResourceGroup.ID != nil { + l["resource_group"] = *snapshotConsistencyGroup.ResourceGroup.ID + } + + if snapshotConsistencyGroup.ServiceTags != nil { + l["service_tags"] = snapshotConsistencyGroup.ServiceTags + } + + tags, err := flex.GetGlobalTagsUsingCRN(meta, *snapshotConsistencyGroup.CRN, "", isUserTagType) + if err != nil { + log.Printf( + "Error on get of resource vpc snapshot consistency group (%s) tags: %s", d.Id(), err) + } + l["tags"] = tags + + accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *snapshotConsistencyGroup.CRN, "", isAccessTagType) + if err != nil { + log.Printf( + "[ERROR] Error on get of resource snapshot (%s) access tags: %s", d.Id(), err) + } + l["access_tags"] = accesstags + + snapshotConsistencyGroupsInfo = append(snapshotConsistencyGroupsInfo, l) + } + + d.SetId(dataSourceIBMIsSnapshotConsistencyGroupsID(d)) + if err = d.Set("snapshot_consistency_groups", snapshotConsistencyGroupsInfo); err != nil { + return diag.FromErr(fmt.Errorf("Error setting snapshot_consistency_groups %s", err)) + } + return nil +} + +// dataSourceIBMIsSnapshotConsistencyGroupsID returns a reasonable ID for the list. +func dataSourceIBMIsSnapshotConsistencyGroupsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} diff --git a/ibm/service/vpc/data_source_ibm_is_snapshot_consistency_groups_test.go b/ibm/service/vpc/data_source_ibm_is_snapshot_consistency_groups_test.go new file mode 100644 index 0000000000..ee04481c60 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_snapshot_consistency_groups_test.go @@ -0,0 +1,61 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMIsSnapshotConsistencyGroupsDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instance-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + deleteSnapshotsOnDelete := "true" + scgname := fmt.Sprintf("tf-snap-cons-grp-name-%d", acctest.RandIntRange(10, 100)) + snapname := fmt.Sprintf("tf-snap-name-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsSnapshotConsistencyGroupsDataSourceConfigBasic(vpcname, subnetname, sshname, publicKey, name, scgname, snapname, deleteSnapshotsOnDelete), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_groups.is_snapshot_consistency_groups", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_groups.is_snapshot_consistency_groups", "snapshot_consistency_groups.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_groups.is_snapshot_consistency_groups", "snapshot_consistency_groups.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_groups.is_snapshot_consistency_groups", "snapshot_consistency_groups.0.crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_groups.is_snapshot_consistency_groups", "snapshot_consistency_groups.0.delete_snapshots_on_delete"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_groups.is_snapshot_consistency_groups", "snapshot_consistency_groups.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_groups.is_snapshot_consistency_groups", "snapshot_consistency_groups.0.lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_groups.is_snapshot_consistency_groups", "snapshot_consistency_groups.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_groups.is_snapshot_consistency_groups", "snapshot_consistency_groups.0.resource_group"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_groups.is_snapshot_consistency_groups", "snapshot_consistency_groups.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_groups.is_snapshot_consistency_groups", "snapshot_consistency_groups.0.snapshots.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_groups.is_snapshot_consistency_groups", "snapshot_consistency_groups.0.snapshots.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_groups.is_snapshot_consistency_groups", "snapshot_consistency_groups.0.snapshots.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_groups.is_snapshot_consistency_groups", "snapshot_consistency_groups.0.snapshots.0.crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_consistency_groups.is_snapshot_consistency_groups", "snapshot_consistency_groups.0.snapshots.0.href"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsSnapshotConsistencyGroupsDataSourceConfigBasic(vpcname, subnetname, sshname, publicKey, name, snapname, scgname, deleteSnapshotsOnDelete string) string { + return testAccCheckIBMIsSnapshotConsistencyGroupConfig(vpcname, subnetname, sshname, publicKey, name, scgname, snapname, deleteSnapshotsOnDelete) + fmt.Sprintf(` + data "ibm_is_snapshot_consistency_groups" "is_snapshot_consistency_groups" { + } +`) +} diff --git a/ibm/service/vpc/data_source_ibm_is_snapshots.go b/ibm/service/vpc/data_source_ibm_is_snapshots.go index 48f0118668..d110df2798 100644 --- a/ibm/service/vpc/data_source_ibm_is_snapshots.go +++ b/ibm/service/vpc/data_source_ibm_is_snapshots.go @@ -23,6 +23,9 @@ const ( isSnapshotSourceSnapshotId = "source_snapshot_id" isSnapshotSourceSnapshotRemoteRegionName = "source_snapshot_remote_region_name" isSnapshotSourceVolumeRemoteRegionName = "snapshot_source_volume_remote_region_name" + isSnapshotConsistencyGroupId = "snapshot_consistency_group_id" + isSnapshotConsistencyGroupCrn = "snapshot_consistency_group_crn" + isSnapshotConsistencyGroup = "snapshot_consistency_group" ) func DataSourceSnapshots() *schema.Resource { @@ -109,6 +112,18 @@ func DataSourceSnapshots() *schema.Resource { Optional: true, }, + isSnapshotConsistencyGroupId: { + Type: schema.TypeString, + Description: "Filters the collection to resources with a source snapshot with the exact snapshot consistency group id.", + Optional: true, + }, + + isSnapshotConsistencyGroupCrn: { + Type: schema.TypeString, + Description: "Filters the collection to resources with a source snapshot with the exact snapshot consistency group crn.", + Optional: true, + }, + isSnapshots: { Type: schema.TypeList, Description: "List of snapshots", @@ -188,6 +203,55 @@ func DataSourceSnapshots() *schema.Resource { }, }, + isSnapshotConsistencyGroup: { + Type: schema.TypeList, + Computed: true, + Description: "The snapshot consistency group which created this snapshot.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN of this snapshot consistency group.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted, and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for the snapshot consistency group.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for the snapshot consistency group.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for the snapshot consistency group. The name is unique across all snapshot consistency groups in the region.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + isSnapshotName: { Type: schema.TypeString, Computed: true, @@ -489,7 +553,14 @@ func getSnapshots(d *schema.ResourceData, meta interface{}) error { sourceVolumeRemoteRegionNameFilter := sourceVolumeRemoteRegionName.(string) listSnapshotOptions.SourceVolumeRemoteRegionName = &sourceVolumeRemoteRegionNameFilter } - + if snapshotConsistencyGroupId, ok := d.GetOk(isSnapshotConsistencyGroupId); ok { + snapshotConsistencyGroupIdFilter := snapshotConsistencyGroupId.(string) + listSnapshotOptions.SnapshotConsistencyGroupID = &snapshotConsistencyGroupIdFilter + } + if snapshotConsistencyGroupCrn, ok := d.GetOk(isSnapshotConsistencyGroupCrn); ok { + snapshotConsistencyGroupCrnFilter := snapshotConsistencyGroupCrn.(string) + listSnapshotOptions.SnapshotConsistencyGroupCRN = &snapshotConsistencyGroupCrnFilter + } snapshots, response, err := sess.ListSnapshots(listSnapshotOptions) if err != nil { return fmt.Errorf("[ERROR] Error fetching snapshots %s\n%s", err, response) @@ -555,6 +626,24 @@ func getSnapshots(d *schema.ResourceData, meta interface{}) error { } l[isSnapshotCopies] = snapshotCopies + // snapshot consistency group + snapshotConsistencyGroupList := []map[string]interface{}{} + if snapshot.SnapshotConsistencyGroup != nil { + snapshotConsistencyGroup := map[string]interface{}{} + snapshotConsistencyGroup["href"] = snapshot.SnapshotConsistencyGroup.Href + snapshotConsistencyGroup["crn"] = snapshot.SnapshotConsistencyGroup.CRN + if snapshot.SnapshotConsistencyGroup.Deleted != nil { + snapshotConsistencyGroupDeletedMap := map[string]interface{}{} + snapshotConsistencyGroupDeletedMap["more_info"] = snapshot.SnapshotConsistencyGroup.Deleted.MoreInfo + snapshotConsistencyGroup["deleted"] = []map[string]interface{}{snapshotConsistencyGroupDeletedMap} + } + snapshotConsistencyGroup["id"] = snapshot.SnapshotConsistencyGroup.ID + snapshotConsistencyGroup["name"] = snapshot.SnapshotConsistencyGroup.Name + snapshotConsistencyGroup["resource_type"] = snapshot.SnapshotConsistencyGroup.ResourceType + snapshotConsistencyGroupList = append(snapshotConsistencyGroupList, snapshotConsistencyGroup) + } + l[isSnapshotConsistencyGroup] = snapshotConsistencyGroupList + if snapshot.UserTags != nil { l[isSnapshotUserTags] = snapshot.UserTags } diff --git a/ibm/service/vpc/resource_ibm_is_backup_policy.go b/ibm/service/vpc/resource_ibm_is_backup_policy.go index 2f9f94e9a6..30aaa3acd1 100644 --- a/ibm/service/vpc/resource_ibm_is_backup_policy.go +++ b/ibm/service/vpc/resource_ibm_is_backup_policy.go @@ -40,8 +40,9 @@ func ResourceIBMIsBackupPolicy() *schema.Resource { Type: schema.TypeString, Optional: true, Default: "volume", + ForceNew: true, ConflictsWith: []string{"match_resource_types"}, - ValidateFunc: validate.InvokeValidator("ibm_is_backup_policy", "match_resource_types"), + ValidateFunc: validate.InvokeValidator("ibm_is_backup_policy", "match_resource_type"), Description: "A resource type this backup policy applies to. Resources that have both a matching type and a matching user tag will be subject to the backup policy.", }, "match_user_tags": &schema.Schema{ @@ -51,6 +52,14 @@ func ResourceIBMIsBackupPolicy() *schema.Resource { Elem: &schema.Schema{Type: schema.TypeString}, Set: schema.HashString, }, + "included_content": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Computed: true, + Set: schema.HashString, + Description: "The included content for backups created using this policy", + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_backup_policy", "included_content")}, + }, "name": &schema.Schema{ Type: schema.TypeString, Required: true, @@ -181,15 +190,22 @@ func ResourceIBMIsBackupPolicyValidator() *validate.ResourceValidator { MaxValueLength: 128, }, ) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "included_content", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Required: true, + AllowedValues: "boot_volume, data_volumes", + }, + ) validateSchema = append(validateSchema, validate.ValidateSchema{ Identifier: "match_resource_type", - ValidateFunctionIdentifier: validate.ValidateRegexpLen, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, Type: validate.TypeString, - Optional: true, - Regexp: `^[a-z][a-z0-9]*(_[a-z0-9]+)*$`, - MinValueLength: 1, - MaxValueLength: 128, + Required: true, + AllowedValues: "instance, volume", }, ) resourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_backup_policy", Schema: validateSchema} @@ -203,27 +219,30 @@ func resourceIBMIsBackupPolicyCreate(context context.Context, d *schema.Resource } createBackupPolicyOptions := &vpcv1.CreateBackupPolicyOptions{} + backupPolicyPrototype := &vpcv1.BackupPolicyPrototype{} if matchResourceType, ok := d.GetOk("match_resource_type"); ok { - matchResourceTypes := matchResourceType.(string) - matchResourceTypesList := []string{matchResourceTypes} - createBackupPolicyOptions.SetMatchResourceTypes(matchResourceTypesList) - } else if _, ok := d.GetOk("match_resource_types"); ok { - createBackupPolicyOptions.SetMatchResourceTypes(flex.ExpandStringList((d.Get("match_resource_types").(*schema.Set)).List())) + backupPolicyPrototype.MatchResourceType = core.StringPtr(matchResourceType.(string)) + } else if matchResourceTypes, ok := d.GetOk("match_resource_types"); ok { + matchResourceTypeList := flex.ExpandStringList((matchResourceTypes.(*schema.Set)).List()) + backupPolicyPrototype.MatchResourceType = core.StringPtr(matchResourceTypeList[0]) + } + if _, ok := d.GetOk("included_content"); ok { + backupPolicyPrototype.IncludedContent = flex.ExpandStringList((d.Get("included_content").(*schema.Set)).List()) } if _, ok := d.GetOk("match_user_tags"); ok { - createBackupPolicyOptions.SetMatchUserTags((flex.ExpandStringList((d.Get("match_user_tags").(*schema.Set)).List()))) + backupPolicyPrototype.MatchUserTags = flex.ExpandStringList((d.Get("match_user_tags").(*schema.Set)).List()) } if _, ok := d.GetOk("name"); ok { - createBackupPolicyOptions.SetName(d.Get("name").(string)) + backupPolicyPrototype.Name = core.StringPtr(d.Get("name").(string)) } if resGroup, ok := d.GetOk("resource_group"); ok { resourceGroupStr := resGroup.(string) resourceGroup := vpcv1.ResourceGroupIdentity{ ID: &resourceGroupStr, } - createBackupPolicyOptions.SetResourceGroup(&resourceGroup) + backupPolicyPrototype.ResourceGroup = &resourceGroup } if _, ok := d.GetOk("scope"); ok { @@ -234,15 +253,16 @@ func resourceIBMIsBackupPolicyCreate(context context.Context, d *schema.Resource bkpPolicyScopePrototype.CRN = core.StringPtr(crnStr) } } - createBackupPolicyOptions.SetScope(&bkpPolicyScopePrototype) + backupPolicyPrototype.Scope = &bkpPolicyScopePrototype } - - backupPolicy, response, err := vpcClient.CreateBackupPolicyWithContext(context, createBackupPolicyOptions) + createBackupPolicyOptions.SetBackupPolicyPrototype(backupPolicyPrototype) + backupPolicyIntf, response, err := vpcClient.CreateBackupPolicyWithContext(context, createBackupPolicyOptions) if err != nil { log.Printf("[DEBUG] CreateBackupPolicyWithContext failed %s\n%s", err, response) return diag.FromErr(fmt.Errorf("[ERROR] CreateBackupPolicyWithContext failed %s\n%s", err, response)) } + backupPolicy := backupPolicyIntf.(*vpcv1.BackupPolicy) d.SetId(*backupPolicy.ID) return resourceIBMIsBackupPolicyRead(context, d, meta) @@ -258,7 +278,7 @@ func resourceIBMIsBackupPolicyRead(context context.Context, d *schema.ResourceDa getBackupPolicyOptions.SetID(d.Id()) - backupPolicy, response, err := vpcClient.GetBackupPolicyWithContext(context, getBackupPolicyOptions) + backupPolicyIntf, response, err := vpcClient.GetBackupPolicyWithContext(context, getBackupPolicyOptions) if err != nil { if response != nil && response.StatusCode == 404 { d.SetId("") @@ -267,19 +287,24 @@ func resourceIBMIsBackupPolicyRead(context context.Context, d *schema.ResourceDa log.Printf("[DEBUG] GetBackupPolicyWithContext failed %s\n%s", err, response) return diag.FromErr(fmt.Errorf("[ERROR] GetBackupPolicyWithContext failed %s\n%s", err, response)) } + backupPolicy := backupPolicyIntf.(*vpcv1.BackupPolicy) - if backupPolicy.MatchResourceTypes != nil { - if err = d.Set("match_resource_types", backupPolicy.MatchResourceTypes); err != nil { + if backupPolicy.MatchResourceType != nil { + matchResourceTypes := *backupPolicy.MatchResourceType + matchResourceTypesList := []string{matchResourceTypes} + if err = d.Set("match_resource_types", matchResourceTypesList); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting match_resource_types: %s", err)) } + if err = d.Set("match_resource_type", backupPolicy.MatchResourceType); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting match_resource_type: %s", err)) + } } - if backupPolicy.MatchResourceTypes != nil { - for _, matchResourceTypes := range backupPolicy.MatchResourceTypes { - if err = d.Set("match_resource_type", matchResourceTypes); err != nil { - return diag.FromErr(fmt.Errorf("[ERROR] Error setting match_resource_type: %s", err)) - } + if backupPolicy.IncludedContent != nil { + if err = d.Set("included_content", backupPolicy.IncludedContent); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting included_content: %s", err)) } } + if backupPolicy.MatchUserTags != nil { if err = d.Set("match_user_tags", backupPolicy.MatchUserTags); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting match_user_tags: %s", err)) @@ -395,6 +420,10 @@ func resourceIBMIsBackupPolicyUpdate(context context.Context, d *schema.Resource patchVals.Name = core.StringPtr(d.Get("name").(string)) hasChange = true } + if d.HasChange("included_content") { + patchVals.IncludedContent = (flex.ExpandStringList((d.Get("included_content").(*schema.Set)).List())) + hasChange = true + } updateBackupPolicyOptions.SetIfMatch(d.Get("version").(string)) if hasChange { updateBackupPolicyOptions.BackupPolicyPatch, _ = patchVals.AsPatch() diff --git a/ibm/service/vpc/resource_ibm_is_snapshot.go b/ibm/service/vpc/resource_ibm_is_snapshot.go index 43d5c737fb..62fa258808 100644 --- a/ibm/service/vpc/resource_ibm_is_snapshot.go +++ b/ibm/service/vpc/resource_ibm_is_snapshot.go @@ -238,6 +238,55 @@ func ResourceIBMSnapshot() *schema.Resource { }, }, + isSnapshotConsistencyGroup: { + Type: schema.TypeList, + Computed: true, + Description: "The snapshot consistency group which created this snapshot.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN of this snapshot consistency group.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted, and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for the snapshot consistency group.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for the snapshot consistency group.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for the snapshot consistency group. The name is unique across all snapshot consistency groups in the region.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + isSnapshotSourceVolume: { Type: schema.TypeString, Optional: true, @@ -643,6 +692,25 @@ func snapshotGet(d *schema.ResourceData, meta interface{}, id string) error { sourceSnapshotList = append(sourceSnapshotList, sourceSnapshot) } d.Set(isSnapshotSourceSnapshot, sourceSnapshotList) + + // snapshot consistency group + snapshotConsistencyGroupList := []map[string]interface{}{} + if snapshot.SnapshotConsistencyGroup != nil { + snapshotConsistencyGroup := map[string]interface{}{} + snapshotConsistencyGroup["href"] = snapshot.SnapshotConsistencyGroup.Href + snapshotConsistencyGroup["crn"] = snapshot.SnapshotConsistencyGroup.CRN + if snapshot.SnapshotConsistencyGroup.Deleted != nil { + snapshotConsistencyGroupDeletedMap := map[string]interface{}{} + snapshotConsistencyGroupDeletedMap["more_info"] = snapshot.SnapshotConsistencyGroup.Deleted.MoreInfo + snapshotConsistencyGroup["deleted"] = []map[string]interface{}{snapshotConsistencyGroupDeletedMap} + } + snapshotConsistencyGroup["id"] = snapshot.SnapshotConsistencyGroup.ID + snapshotConsistencyGroup["name"] = snapshot.SnapshotConsistencyGroup.Name + snapshotConsistencyGroup["resource_type"] = snapshot.SnapshotConsistencyGroup.ResourceType + snapshotConsistencyGroupList = append(snapshotConsistencyGroupList, snapshotConsistencyGroup) + } + d.Set(isSnapshotConsistencyGroup, snapshotConsistencyGroupList) + snapshotCopies := []map[string]interface{}{} if snapshot.Copies != nil { for _, copiesItem := range snapshot.Copies { diff --git a/ibm/service/vpc/resource_ibm_is_snapshot_consistency_group.go b/ibm/service/vpc/resource_ibm_is_snapshot_consistency_group.go new file mode 100644 index 0000000000..c73112fb3d --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_snapshot_consistency_group.go @@ -0,0 +1,815 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "os" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func ResourceIBMIsSnapshotConsistencyGroup() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMIsSnapshotConsistencyGroupCreate, + ReadContext: resourceIBMIsSnapshotConsistencyGroupRead, + UpdateContext: resourceIBMIsSnapshotConsistencyGroupUpdate, + DeleteContext: resourceIBMIsSnapshotConsistencyGroupDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "delete_snapshots_on_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Indicates whether deleting the snapshot consistency group will also delete the snapshots in the group.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_is_snapshot_consistency_group", "name"), + Description: "The name for this snapshot consistency group. The name is unique across all snapshot consistency groups in the region.", + }, + "resource_group": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Description: "Resource group Id", + }, + "snapshots": { + Type: schema.TypeList, + Required: true, + Description: "The member snapshots that are data-consistent with respect to captured time. (may be[deleted](https://cloud.ibm.com/apidocs/vpc#deleted-resources)).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The name for this snapshot. The name is unique across all snapshots in the region.", + }, + "source_volume": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The volume to create this snapshot from.", + }, + "tags": { + Type: schema.TypeSet, + Optional: true, + Set: flex.ResourceIBMVPCHash, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_snapshot_consistency_group", "tags")}, + Description: "User Tags for the snapshot", + }, + }, + }, + }, + "snapshot_reference": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The member snapshots that are data-consistent with respect to captured time. (may be[deleted](https://cloud.ibm.com/apidocs/vpc#deleted-resources)).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN of this snapshot.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted, and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this snapshot.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this snapshot.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this snapshot. The name is unique across all snapshots in the region.", + }, + "remote": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource is remote to this region,and identifies the native region.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this region.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this region.", + }, + }, + }, + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "backup_policy_plan": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, the backup policy plan which created this snapshot consistency group.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource has been deleted, and providessome supplementary information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "more_info": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this backup policy plan.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this backup policy plan.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this backup policy plan. The name is unique across all plans in the backup policy.", + }, + "remote": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, this property indicates the referenced resource is remote to this region,and identifies the native region.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this region.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this region.", + }, + }, + }, + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that this snapshot consistency group was created.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN of this snapshot consistency group.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this snapshot consistency group.", + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of this snapshot consistency group.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "service_tags": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The [service tags](https://cloud.ibm.com/apidocs/tagging#types-of-tags)[`is.instance:` prefix](https://cloud.ibm.com/docs/vpc?topic=vpc-snapshots-vpc-faqs) associated with this snapshot consistency group.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "tags": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_snapshot_consistency_group", "tags")}, + Set: flex.ResourceIBMVPCHash, + Description: "Snapshot Consistency Group tags list", + }, + "access_tags": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_snapshot_consistency_group", "access_tags")}, + Set: flex.ResourceIBMVPCHash, + Description: "List of access management tags", + }, + }, + } +} + +func ResourceIBMIsSnapshotConsistencyGroupValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9]|[0-9][-a-z0-9]*([a-z]|[-a-z][-a-z0-9]*[a-z0-9]))$`, + MinValueLength: 1, + MaxValueLength: 63, + }, + ) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[A-Za-z0-9:_ .-]+$`, + MinValueLength: 1, + MaxValueLength: 128, + }, + ) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "access_tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([A-Za-z0-9_.-]|[A-Za-z0-9_.-][A-Za-z0-9_ .-]*[A-Za-z0-9_.-]):([A-Za-z0-9_.-]|[A-Za-z0-9_.-][A-Za-z0-9_ .-]*[A-Za-z0-9_.-])$`, + MinValueLength: 1, + MaxValueLength: 128}) + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_snapshot_consistency_group", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMIsSnapshotConsistencyGroupCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + createSnapshotConsistencyGroupOptions := &vpcv1.CreateSnapshotConsistencyGroupOptions{} + snapshotConsistencyGroupPrototype := &vpcv1.SnapshotConsistencyGroupPrototype{} + + if _, ok := d.GetOk("delete_snapshots_on_delete"); ok { + snapshotConsistencyGroupPrototype.DeleteSnapshotsOnDelete = core.BoolPtr(d.Get("delete_snapshots_on_delete").(bool)) + } + + if _, ok := d.GetOk("name"); ok { + snapshotConsistencyGroupPrototype.Name = core.StringPtr(d.Get("name").(string)) + } + + if rgrp, ok := d.GetOk("resource_group"); ok { + rg := rgrp.(string) + snapshotConsistencyGroupPrototype.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &rg, + } + } + var snapshotConsistencyGroupPrototypeSnapshotsItemArray []vpcv1.SnapshotConsistencyGroupPrototypeSnapshotsItem + snapshotsArray := d.Get("snapshots").([]interface{}) + for _, snapshot := range snapshotsArray { + snapshotVal := snapshot.(map[string]interface{}) + snapshotConsistencyGroupPrototypeSnapshotsItem := &vpcv1.SnapshotConsistencyGroupPrototypeSnapshotsItem{} + + volume := snapshotVal["source_volume"].(string) + snapshotConsistencyGroupPrototypeSnapshotsItem.SourceVolume = &vpcv1.VolumeIdentity{ + ID: &volume, + } + name := snapshotVal["name"].(string) + if name != "" { + snapshotConsistencyGroupPrototypeSnapshotsItem.Name = &name + } + + userTags := snapshotVal["tags"].(*schema.Set) + if userTags != nil && userTags.Len() != 0 { + userTagsArray := make([]string, userTags.Len()) + for i, userTag := range userTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + schematicTags := os.Getenv("IC_ENV_TAGS") + var envTags []string + if schematicTags != "" { + envTags = strings.Split(schematicTags, ",") + userTagsArray = append(userTagsArray, envTags...) + } + snapshotConsistencyGroupPrototypeSnapshotsItem.UserTags = userTagsArray + } + snapshotConsistencyGroupPrototypeSnapshotsItemArray = append(snapshotConsistencyGroupPrototypeSnapshotsItemArray, *snapshotConsistencyGroupPrototypeSnapshotsItem) + } + snapshotConsistencyGroupPrototype.Snapshots = snapshotConsistencyGroupPrototypeSnapshotsItemArray + + createSnapshotConsistencyGroupOptions.SnapshotConsistencyGroupPrototype = snapshotConsistencyGroupPrototype + snapshotConsistencyGroup, response, err := vpcClient.CreateSnapshotConsistencyGroupWithContext(context, createSnapshotConsistencyGroupOptions) + if err != nil { + log.Printf("[DEBUG] CreateSnapshotConsistencyGroupWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("CreateSnapshotConsistencyGroupWithContext failed %s\n%s", err, response)) + } + + d.SetId(*snapshotConsistencyGroup.ID) + + _, err = isWaitForSnapshotConsistencyGroupAvailable(vpcClient, d.Id(), d.Timeout(schema.TimeoutCreate)) + + if err != nil { + return diag.FromErr(err) + } + + v := os.Getenv("IC_ENV_TAGS") + if _, ok := d.GetOk("tags"); ok || v != "" { + oldList, newList := d.GetChange("tags") + err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *snapshotConsistencyGroup.CRN, "", isUserTagType) + if err != nil { + log.Printf( + "Error on create of resource vpc snapshot consistency group (%s) tags: %s", d.Id(), err) + } + } + + if _, ok := d.GetOk("access_tags"); ok { + oldList, newList := d.GetChange("access_tags") + err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *snapshotConsistencyGroup.CRN, "", isAccessTagType) + if err != nil { + log.Printf( + "Error on create of resource snapshot consistency group (%s) access tags: %s", d.Id(), err) + } + } + + return resourceIBMIsSnapshotConsistencyGroupRead(context, d, meta) +} + +func isWaitForSnapshotConsistencyGroupAvailable(sess *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for Snapshot Consistency Group(%s) to be available.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"pending"}, + Target: []string{"stable", "failed"}, + Refresh: isSnapshotConsistencyGroupRefreshFunc(sess, id), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isSnapshotConsistencyGroupRefreshFunc(vpcClient *vpcv1.VpcV1, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + getSnapshotConsistencyGroupOptions := &vpcv1.GetSnapshotConsistencyGroupOptions{} + getSnapshotConsistencyGroupOptions.SetID(id) + + snapshotConsistencyGroup, response, err := vpcClient.GetSnapshotConsistencyGroup(getSnapshotConsistencyGroupOptions) + if err != nil { + log.Printf("[DEBUG] GetSnapshotConsistencyGroupWithContext failed %s\n%s", err, response) + return nil, "failed", fmt.Errorf("[ERROR] Error GetSnapshotConsistencyGroupWithContext failed : %s\n%s", err, response) + } + + if *snapshotConsistencyGroup.LifecycleState == "stable" { + return snapshotConsistencyGroup, *snapshotConsistencyGroup.LifecycleState, nil + } else if *snapshotConsistencyGroup.LifecycleState == "failed" { + return snapshotConsistencyGroup, *snapshotConsistencyGroup.LifecycleState, + fmt.Errorf("Snapshot Consistency Group (%s) went into failed state during the operation \n [WARNING] Running terraform apply again will remove the tainted snapshot consistency group and attempt to create the snapshot again replacing the previous configuration", *snapshotConsistencyGroup.ID) + } + + return snapshotConsistencyGroup, "pending", nil + } +} + +func isWaitForSnapshotConsistencyGroupUpdate(sess *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for Snapshot Consistency Group (%s) to be available.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"updating"}, + Target: []string{"stable", "failed"}, + Refresh: isSnapshotUpdateConsistencyGroupRefreshFunc(sess, id), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + return stateConf.WaitForState() +} + +func isSnapshotUpdateConsistencyGroupRefreshFunc(vpcClient *vpcv1.VpcV1, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + getSnapshotConsistencyGroupOptions := &vpcv1.GetSnapshotConsistencyGroupOptions{} + getSnapshotConsistencyGroupOptions.SetID(id) + + snapshotConsistencyGroup, response, err := vpcClient.GetSnapshotConsistencyGroup(getSnapshotConsistencyGroupOptions) + if err != nil { + log.Printf("[DEBUG] GetSnapshotConsistencyGroupWithContext failed %s\n%s", err, response) + return nil, "failed", fmt.Errorf("[ERROR] Error GetSnapshotConsistencyGroupWithContext failed : %s\n%s", err, response) + } + + if *snapshotConsistencyGroup.LifecycleState == "stable" || *snapshotConsistencyGroup.LifecycleState == "failed" { + return snapshotConsistencyGroup, *snapshotConsistencyGroup.LifecycleState, nil + } else if *snapshotConsistencyGroup.LifecycleState == isSnapshotFailed { + return snapshotConsistencyGroup, *snapshotConsistencyGroup.LifecycleState, fmt.Errorf("Snapshot Consistency Group (%s) went into failed state during the operation \n [WARNING] Running terraform apply again will remove the tainted snapshot consistency group and attempt to create the snapshot consistency group again replacing the previous configuration", *snapshotConsistencyGroup.ID) + } + + return snapshotConsistencyGroup, isSnapshotUpdating, nil + } +} + +func isWaitForSnapshotConsistencyGroupDeleted(sess *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for Snapshot Consistency Group (%s) to be deleted.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"deleting"}, + Target: []string{"deleted", "failed"}, + Refresh: isSnapshotDeleteConsistencyGroupRefreshFunc(sess, id), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isSnapshotDeleteConsistencyGroupRefreshFunc(vpcClient *vpcv1.VpcV1, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + log.Printf("[DEBUG] Refresh function for Snapshot Consistency Group delete.") + + getSnapshotConsistencyGroupOptions := &vpcv1.GetSnapshotConsistencyGroupOptions{} + getSnapshotConsistencyGroupOptions.SetID(id) + + snapshotConsistencyGroup, response, err := vpcClient.GetSnapshotConsistencyGroup(getSnapshotConsistencyGroupOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return snapshotConsistencyGroup, "deleted", nil + } + return nil, "failed", fmt.Errorf("[ERROR] The Snapshot Consistency Group %s failed to delete: %s\n%s", id, err, response) + } + return snapshotConsistencyGroup, *snapshotConsistencyGroup.LifecycleState, nil + } +} + +func resourceIBMIsSnapshotConsistencyGroupRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + getSnapshotConsistencyGroupOptions := &vpcv1.GetSnapshotConsistencyGroupOptions{} + getSnapshotConsistencyGroupOptions.SetID(d.Id()) + + snapshotConsistencyGroup, response, err := vpcClient.GetSnapshotConsistencyGroupWithContext(context, getSnapshotConsistencyGroupOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetSnapshotConsistencyGroupWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetSnapshotConsistencyGroupWithContext failed %s\n%s", err, response)) + } + + if !core.IsNil(snapshotConsistencyGroup.DeleteSnapshotsOnDelete) { + if err = d.Set("delete_snapshots_on_delete", snapshotConsistencyGroup.DeleteSnapshotsOnDelete); err != nil { + return diag.FromErr(fmt.Errorf("Error setting delete_snapshots_on_delete: %s", err)) + } + } + if !core.IsNil(snapshotConsistencyGroup.Name) { + if err = d.Set("name", snapshotConsistencyGroup.Name); err != nil { + return diag.FromErr(fmt.Errorf("Error setting name: %s", err)) + } + } + if !core.IsNil(snapshotConsistencyGroup.ResourceGroup) && !core.IsNil(snapshotConsistencyGroup.ResourceGroup.ID) { + d.Set("resource_group", snapshotConsistencyGroup.ResourceGroup.ID) + } + if !core.IsNil(snapshotConsistencyGroup.Snapshots) { + snapshots := []map[string]interface{}{} + for _, snapshotsItem := range snapshotConsistencyGroup.Snapshots { + snapshotsItemMap, err := resourceIBMIsSnapshotConsistencyGroupSnapshotConsistencyGroupSnapshotsItemToMap(&snapshotsItem) + if err != nil { + return diag.FromErr(err) + } + snapshots = append(snapshots, snapshotsItemMap) + } + if err = d.Set("snapshot_reference", snapshots); err != nil { + return diag.FromErr(fmt.Errorf("Error setting snapshots: %s", err)) + } + } + if !core.IsNil(snapshotConsistencyGroup.BackupPolicyPlan) { + backupPolicyPlanMap, err := resourceIBMIsSnapshotConsistencyGroupBackupPolicyPlanReferenceToMap(snapshotConsistencyGroup.BackupPolicyPlan) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("backup_policy_plan", []map[string]interface{}{backupPolicyPlanMap}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting backup_policy_plan: %s", err)) + } + } else { + if err = d.Set("backup_policy_plan", []map[string]interface{}{}); err != nil { + return diag.FromErr(fmt.Errorf("Error setting backup_policy_plan: %s", err)) + } + } + if err = d.Set("created_at", flex.DateTimeToString(snapshotConsistencyGroup.CreatedAt)); err != nil { + return diag.FromErr(fmt.Errorf("Error setting created_at: %s", err)) + } + if err = d.Set("crn", snapshotConsistencyGroup.CRN); err != nil { + return diag.FromErr(fmt.Errorf("Error setting crn: %s", err)) + } + if err = d.Set("href", snapshotConsistencyGroup.Href); err != nil { + return diag.FromErr(fmt.Errorf("Error setting href: %s", err)) + } + if err = d.Set("lifecycle_state", snapshotConsistencyGroup.LifecycleState); err != nil { + return diag.FromErr(fmt.Errorf("Error setting lifecycle_state: %s", err)) + } + if err = d.Set("resource_type", snapshotConsistencyGroup.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("Error setting resource_type: %s", err)) + } + if err = d.Set("service_tags", snapshotConsistencyGroup.ServiceTags); err != nil { + return diag.FromErr(fmt.Errorf("Error setting service_tags: %s", err)) + } + tags, err := flex.GetGlobalTagsUsingCRN(meta, *snapshotConsistencyGroup.CRN, "", isUserTagType) + if err != nil { + log.Printf( + "Error on get of resource vpc snapshot consistency group (%s) tags: %s", d.Id(), err) + } + d.Set("tags", tags) + + accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *snapshotConsistencyGroup.CRN, "", isAccessTagType) + if err != nil { + log.Printf( + "Error on get of resource VPC snapshot consistency group (%s) access tags: %s", d.Id(), err) + } + d.Set("access_tags", accesstags) + return nil +} + +func resourceIBMIsSnapshotConsistencyGroupUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + updateSnapshotConsistencyGroupOptions := &vpcv1.UpdateSnapshotConsistencyGroupOptions{} + updateSnapshotConsistencyGroupOptions.SetID(d.Id()) + hasChange := false + + if d.HasChange("tags") { + getSnapshotConsistencyGroupOptions := &vpcv1.GetSnapshotConsistencyGroupOptions{} + getSnapshotConsistencyGroupOptions.SetID(d.Id()) + + snapshotConsistencyGroup, response, err := vpcClient.GetSnapshotConsistencyGroupWithContext(context, getSnapshotConsistencyGroupOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetSnapshotConsistencyGroupWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetSnapshotConsistencyGroupWithContext failed %s\n%s", err, response)) + } + + oldList, newList := d.GetChange("tags") + err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *snapshotConsistencyGroup.CRN, "", isUserTagType) + if err != nil { + log.Printf( + "Error on update of resource vpc snapshot consistency group (%s) tags: %s", d.Id(), err) + } + } + if d.HasChange("access_tags") { + getSnapshotConsistencyGroupOptions := &vpcv1.GetSnapshotConsistencyGroupOptions{} + getSnapshotConsistencyGroupOptions.SetID(d.Id()) + + snapshotConsistencyGroup, response, err := vpcClient.GetSnapshotConsistencyGroupWithContext(context, getSnapshotConsistencyGroupOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetSnapshotConsistencyGroupWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetSnapshotConsistencyGroupWithContext failed %s\n%s", err, response)) + } + + oldList, newList := d.GetChange("access_tags") + err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *snapshotConsistencyGroup.CRN, "", isAccessTagType) + if err != nil { + log.Printf( + "Error on update of resource VPC snapshot consistency group (%s) access tags: %s", d.Id(), err) + } + } + + patchVals := &vpcv1.SnapshotConsistencyGroupPatch{} + if d.HasChange("delete_snapshots_on_delete") { + newDeleteSnapshotsOnDelete := d.Get("delete_snapshots_on_delete").(bool) + patchVals.DeleteSnapshotsOnDelete = &newDeleteSnapshotsOnDelete + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + getSnapshotConsistencyGroupOptions := &vpcv1.GetSnapshotConsistencyGroupOptions{} + getSnapshotConsistencyGroupOptions.SetID(d.Id()) + + _, response, err := vpcClient.GetSnapshotConsistencyGroupWithContext(context, getSnapshotConsistencyGroupOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + log.Printf("[DEBUG] GetSnapshotConsistencyGroupWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("GetSnapshotConsistencyGroupWithContext failed %s\n%s", err, response)) + } + updateSnapshotConsistencyGroupOptions.SetIfMatch(response.Headers.Get("Etag")) + + if hasChange { + updateSnapshotConsistencyGroupOptions.SnapshotConsistencyGroupPatch, _ = patchVals.AsPatch() + _, response, err := vpcClient.UpdateSnapshotConsistencyGroupWithContext(context, updateSnapshotConsistencyGroupOptions) + if err != nil { + log.Printf("[DEBUG] UpdateSnapshotConsistencyGroupWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("UpdateSnapshotConsistencyGroupWithContext failed %s\n%s", err, response)) + } + _, err = isWaitForSnapshotConsistencyGroupUpdate(vpcClient, d.Id(), d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + } + + return resourceIBMIsSnapshotConsistencyGroupRead(context, d, meta) +} + +func resourceIBMIsSnapshotConsistencyGroupDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + return diag.FromErr(err) + } + + deleteSnapshotConsistencyGroupOptions := &vpcv1.DeleteSnapshotConsistencyGroupOptions{} + + deleteSnapshotConsistencyGroupOptions.SetID(d.Id()) + + _, response, err := vpcClient.DeleteSnapshotConsistencyGroupWithContext(context, deleteSnapshotConsistencyGroupOptions) + if err != nil { + log.Printf("[DEBUG] DeleteSnapshotConsistencyGroupWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("DeleteSnapshotConsistencyGroupWithContext failed %s\n%s", err, response)) + } + + _, err = isWaitForSnapshotConsistencyGroupDeleted(vpcClient, d.Id(), d.Timeout(schema.TimeoutDelete)) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("") + + return nil +} + +func resourceIBMIsSnapshotConsistencyGroupResourceGroupReferenceToMap(model *vpcv1.ResourceGroupReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = model.Href + modelMap["id"] = model.ID + modelMap["name"] = model.Name + return modelMap, nil +} + +func resourceIBMIsSnapshotConsistencyGroupSnapshotConsistencyGroupSnapshotsItemToMap(model *vpcv1.SnapshotConsistencyGroupSnapshotsItem) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = model.CRN + if model.Deleted != nil { + deletedMap, err := resourceIBMIsSnapshotConsistencyGroupSnapshotReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap["deleted"] = []map[string]interface{}{deletedMap} + } + if model.Href != nil { + modelMap["href"] = model.Href + } + if model.ID != nil { + modelMap["id"] = model.ID + } + if model.Name != nil { + modelMap["name"] = model.Name + } + if model.Remote != nil { + remoteMap, err := resourceIBMIsSnapshotConsistencyGroupSnapshotRemoteToMap(model.Remote) + if err != nil { + return modelMap, err + } + modelMap["remote"] = []map[string]interface{}{remoteMap} + } + if model.ResourceType != nil { + modelMap["resource_type"] = model.ResourceType + } + return modelMap, nil +} + +func resourceIBMIsSnapshotConsistencyGroupSnapshotReferenceDeletedToMap(model *vpcv1.SnapshotReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.MoreInfo != nil { + modelMap["more_info"] = model.MoreInfo + } + return modelMap, nil +} + +func resourceIBMIsSnapshotConsistencyGroupSnapshotRemoteToMap(model *vpcv1.SnapshotRemote) (map[string]interface{}, error) { + regionMap := make(map[string]interface{}) + if model.Region != nil { + regionMap, err := resourceIBMIsSnapshotConsistencyGroupRegionReferenceToMap(model.Region) + if err != nil { + return regionMap, err + } + return regionMap, nil + } + return regionMap, nil +} + +func resourceIBMIsSnapshotConsistencyGroupRegionReferenceToMap(model *vpcv1.RegionReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = model.Href + modelMap["name"] = model.Name + return modelMap, nil +} + +func resourceIBMIsSnapshotConsistencyGroupBackupPolicyPlanReferenceToMap(model *vpcv1.BackupPolicyPlanReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := resourceIBMIsSnapshotConsistencyGroupBackupPolicyPlanReferenceDeletedToMap(model.Deleted) + if err != nil { + return modelMap, err + } + modelMap["deleted"] = []map[string]interface{}{deletedMap} + } + modelMap["href"] = model.Href + modelMap["id"] = model.ID + modelMap["name"] = model.Name + if model.Remote != nil { + remoteMap, err := resourceIBMIsSnapshotConsistencyGroupBackupPolicyPlanRemoteToMap(model.Remote) + if err != nil { + return modelMap, err + } + modelMap["remote"] = []map[string]interface{}{remoteMap} + } + modelMap["resource_type"] = model.ResourceType + return modelMap, nil +} + +func resourceIBMIsSnapshotConsistencyGroupBackupPolicyPlanReferenceDeletedToMap(model *vpcv1.BackupPolicyPlanReferenceDeleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = model.MoreInfo + return modelMap, nil +} + +func resourceIBMIsSnapshotConsistencyGroupBackupPolicyPlanRemoteToMap(model *vpcv1.BackupPolicyPlanRemote) (map[string]interface{}, error) { + regionMap := make(map[string]interface{}) + if model.Region != nil { + regionMap, err := resourceIBMIsSnapshotConsistencyGroupRegionReferenceToMap(model.Region) + if err != nil { + return regionMap, err + } + return regionMap, nil + } + return regionMap, nil +} diff --git a/ibm/service/vpc/resource_ibm_is_snapshot_consistency_group_test.go b/ibm/service/vpc/resource_ibm_is_snapshot_consistency_group_test.go new file mode 100644 index 0000000000..5637ad4799 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_snapshot_consistency_group_test.go @@ -0,0 +1,166 @@ +// Copyright IBM Corp. 2023 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + "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" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func TestAccIBMIsSnapshotConsistencyGroupBasic(t *testing.T) { + var conf vpcv1.SnapshotConsistencyGroup + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instance-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + deleteSnapshotsOnDelete := "true" + scgname := fmt.Sprintf("tf-snap-cons-grp-name-%d", acctest.RandIntRange(10, 100)) + deleteSnapshotsOnDeleteUpdate := "false" + snapname := fmt.Sprintf("tf-snap-name-%d", acctest.RandIntRange(10, 100)) + scgnameUpdate := fmt.Sprintf("tf-snap-cons-grp-name-update-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsSnapshotConsistencyGroupDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsSnapshotConsistencyGroupConfig(vpcname, subnetname, sshname, publicKey, name, scgname, snapname, deleteSnapshotsOnDelete), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsSnapshotConsistencyGroupExists("ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", conf), + resource.TestCheckResourceAttr("ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "delete_snapshots_on_delete", deleteSnapshotsOnDelete), + resource.TestCheckResourceAttr("ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "name", scgname), + resource.TestCheckResourceAttrSet("ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "id"), + resource.TestCheckResourceAttrSet("ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "name"), + resource.TestCheckResourceAttrSet("ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "crn"), + resource.TestCheckResourceAttrSet("ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "href"), + resource.TestCheckResourceAttrSet("ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "lifecycle_state"), + resource.TestCheckResourceAttrSet("ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "snapshot_reference.0.id"), + resource.TestCheckResourceAttrSet("ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "snapshot_reference.0.crn"), + resource.TestCheckResourceAttrSet("ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "snapshot_reference.0.name"), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMIsSnapshotConsistencyGroupConfig(vpcname, subnetname, sshname, publicKey, name, scgnameUpdate, snapname, deleteSnapshotsOnDeleteUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "delete_snapshots_on_delete", deleteSnapshotsOnDeleteUpdate), + resource.TestCheckResourceAttr("ibm_is_snapshot_consistency_group.is_snapshot_consistency_group", "name", scgnameUpdate), + ), + }, + }, + }) +} + +func testAccCheckIBMIsSnapshotConsistencyGroupConfig(vpcname, subnetname, sshname, publicKey, name, snapname, scgname, deleteSnapshotsOnDelete string) string { + return fmt.Sprintf(` + + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + } + + resource "ibm_is_snapshot_consistency_group" "is_snapshot_consistency_group" { + delete_snapshots_on_delete = "%s" + snapshots { + name = "%s" + source_volume = ibm_is_instance.testacc_instance.volume_attachments[0].volume_id + } + name = "%s" + } + `, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, name, "r134-f47cc24c-e020-4db5-ad96-1e5be8b5853b", acc.InstanceProfileName, acc.ISZoneName, deleteSnapshotsOnDelete, scgname, snapname) +} + +func testAccCheckIBMIsSnapshotConsistencyGroupExists(n string, obj vpcv1.SnapshotConsistencyGroup) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + vpcClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + if err != nil { + return err + } + + getSnapshotConsistencyGroupOptions := &vpcv1.GetSnapshotConsistencyGroupOptions{} + + getSnapshotConsistencyGroupOptions.SetID(rs.Primary.ID) + + snapshotConsistencyGroup, _, err := vpcClient.GetSnapshotConsistencyGroup(getSnapshotConsistencyGroupOptions) + if err != nil { + return err + } + + obj = *snapshotConsistencyGroup + return nil + } +} + +func testAccCheckIBMIsSnapshotConsistencyGroupDestroy(s *terraform.State) error { + vpcClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_snapshot_consistency_group" { + continue + } + + getSnapshotConsistencyGroupOptions := &vpcv1.GetSnapshotConsistencyGroupOptions{} + + getSnapshotConsistencyGroupOptions.SetID(rs.Primary.ID) + + // Try to find the key + _, response, err := vpcClient.GetSnapshotConsistencyGroup(getSnapshotConsistencyGroupOptions) + + if err == nil { + return fmt.Errorf("SnapshotConsistencyGroup still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for SnapshotConsistencyGroup (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_vpc_dns_resolution_binding.go b/ibm/service/vpc/resource_ibm_is_vpc_dns_resolution_binding.go index 3ec4a1ff60..b83c374d5b 100644 --- a/ibm/service/vpc/resource_ibm_is_vpc_dns_resolution_binding.go +++ b/ibm/service/vpc/resource_ibm_is_vpc_dns_resolution_binding.go @@ -404,7 +404,7 @@ func resourceIBMIsVPCDnsResolutionBindingDelete(context context.Context, d *sche deleteVPCDnsResolutionBindingOptions.SetVPCID(vpcId) deleteVPCDnsResolutionBindingOptions.SetID(id) - response, err := sess.DeleteVPCDnsResolutionBindingWithContext(context, deleteVPCDnsResolutionBindingOptions) + _, response, err := sess.DeleteVPCDnsResolutionBindingWithContext(context, deleteVPCDnsResolutionBindingOptions) if err != nil { log.Printf("[DEBUG] DeleteVPCDnsResolutionBindingWithContext failed %s\n%s", err, response) if response.StatusCode != 404 { diff --git a/website/docs/d/is_backup_policies.html.markdown b/website/docs/d/is_backup_policies.html.markdown index 3e36540ebe..40b6c6e186 100644 --- a/website/docs/d/is_backup_policies.html.markdown +++ b/website/docs/d/is_backup_policies.html.markdown @@ -54,9 +54,17 @@ In addition to all argument reference list, you can access the following attribu - `health_state` - (String) The health of this resource. - `href` - (String) The URL for this backup policy. - `id` - (String) The unique identifier for this backup policy. + - `included_content` - (Optional, List) The included content for backups created using this policy. + + ~> **Note** + `boot_volume`: Include the instance's boot volume.
+ `data_volumes`: Include the instance's data volumes. - `last_job_completed_at` - (String) he date and time that the most recent job for this backup policy completed. - `lifecycle_state` - (String) The lifecycle state of the backup policy. - `match_resource_types` - (List) A resource type this backup policy applies to. Resources that have both a matching type and a matching user tag will be subject to the backup policy. + ~> **Note** + `match_resource_types` is deprecated. Please use `match_resource_type` instead. + - `match_resource_type` - (Optional, String) The resource type this backup policy will apply to. Resources that have both a matching type and a matching user tag will be subject to the backup policy. - `match_user_tags` - (List) The user tags this backup policy applies to. Resources that have both a matching user tag and a matching type will be subject to the backup policy. - `name` - (String) The unique user-defined name for this backup policy. - `plans` - (List) The plans for the backup policy. diff --git a/website/docs/d/is_backup_policy.html.markdown b/website/docs/d/is_backup_policy.html.markdown index 6513f31bfa..ce883610be 100644 --- a/website/docs/d/is_backup_policy.html.markdown +++ b/website/docs/d/is_backup_policy.html.markdown @@ -53,6 +53,9 @@ In addition to all argument reference list, you can access the following attribu - `last_job_completed_at` - (String) he date and time that the most recent job for this backup policy completed. - `lifecycle_state` - (String) The lifecycle state of the backup policy. - `match_resource_types` - (List) A resource type this backup policy applies to. Resources that have both a matching type and a matching user tag will be subject to the backup policy. +~> **Note** + `match_resource_types` is deprecated. Please use `match_resource_type` instead. +- `match_resource_type` - (Optional, String) The resource type this backup policy will apply to. Resources that have both a matching type and a matching user tag will be subject to the backup policy. - `match_user_tags` - (List) The user tags this backup policy applies to. Resources that have both a matching user tag and a matching type will be subject to the backup policy. - `name` - (String) The unique user-defined name for this backup policy. - `plans` - (List) The plans for the backup policy. diff --git a/website/docs/d/is_backup_policy_job.html.markdown b/website/docs/d/is_backup_policy_job.html.markdown index 18f23ce8b3..3f817ab700 100644 --- a/website/docs/d/is_backup_policy_job.html.markdown +++ b/website/docs/d/is_backup_policy_job.html.markdown @@ -72,7 +72,24 @@ In addition to all argument references listed, you can access the following attr - `href` - (String) The URL for this volume. - `id` - (String) The unique identifier for this volume. - `name` - (String) The unique user-defined name for this volume. + - `remote` - (List) If present, this property indicates that the referenced resource is remote to this region, and identifies the native region. + Nested scheme for `remote`: + - `href` - (String) The URL for this region. + - `name` - (String) The globally unique name for this region. + - `resource_type` - (String) The resource type. +- `source_instance` - (List) The source instance this backup was created from (may be [deleted](https://cloud.ibm.com/apidocs/vpc#deleted-resources)). + + Nested scheme for `source_instance`: + - `crn` - (String) The CRN for this virtual server instance. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this virtual server instance. + - `id` - (String) The unique identifier for this virtual server instance. + - `name` - (String) The unique user-defined name for this virtual server instance. + - `resource_type` - (String) The resource type. - `status` - (String) The status of the backup policy job.The enumerated values for this property will expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the backup policy job on which the unexpected property value was encountered. - `status_reasons` - (List) The reasons for the current status (if any).The enumerated reason code values for this property will expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected reason code was encountered. diff --git a/website/docs/d/is_backup_policy_jobs.html.markdown b/website/docs/d/is_backup_policy_jobs.html.markdown index 5dafd73fe3..b686469335 100644 --- a/website/docs/d/is_backup_policy_jobs.html.markdown +++ b/website/docs/d/is_backup_policy_jobs.html.markdown @@ -64,6 +64,18 @@ In addition to all argument references listed, you can access the following attr - `created_at` - (String) The date and time that the backup policy job was created. - `href` - (String) The URL for this backup policy job. - `id` - (String) The unique identifier for this backup policy job. + - `source_instance` - (List) The source instance this backup was created from (may be [deleted](https://cloud.ibm.com/apidocs/vpc#deleted-resources)). + + Nested scheme for `source_instance`: + - `crn` - (String) The CRN for this virtual server instance. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and providessome supplementary information. + + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this virtual server instance. + - `id` - (String) The unique identifier for this virtual server instance. + - `name` - (String) The unique user-defined name for this virtual server instance. + - `resource_type` - (String) The resource type. - `job_type` - (String) The type of backup policy job.The enumerated values for this property will expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the backup policy job on which the unexpected property value was encountered. - `resource_type` - (String) The resource type. - `source_volume` - (List) The source volume this backup was created from (may be [deleted](https://cloud.ibm.com/apidocs/vpc#deleted-resources)) @@ -76,7 +88,13 @@ In addition to all argument references listed, you can access the following attr - `more_info` - (String) Link to documentation about deleted resources. - `href` - (String) The URL for this volume. - `id` - (String) The unique identifier for this volume. + - `remote` - (List) If present, this property indicates that the referenced resource is remote to this region, and identifies the native region. + + Nested scheme for `remote`: + - `href` - (String) The URL for this region. + - `name` - (String) The globally unique name for this region. - `name` - (String) The unique user-defined name for this volume. + - `resource_type` - (String) The resource type. - `status` - (String) The status of the backup policy job.The enumerated values for this property will expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the backup policy job on which the unexpected property value was encountered. - `status_reasons` - (List) The reasons for the current status (if any).The enumerated reason code values for this property will expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected reason code was encountered. diff --git a/website/docs/d/is_backup_policy_plan.html.markdown b/website/docs/d/is_backup_policy_plan.html.markdown index a0e9af1ebd..13a8e3a7bc 100644 --- a/website/docs/d/is_backup_policy_plan.html.markdown +++ b/website/docs/d/is_backup_policy_plan.html.markdown @@ -43,6 +43,11 @@ Review the argument references that you can specify for your data source. In addition to all argument reference list, you can access the following attribute references after your data source is created. - `id` - The unique identifier of the BackupPolicyPlan. +- `included_content` - (Optional, List) The included content for backups created using this policy. + +~> **Note** + `boot_volume`: Include the instance's boot volume.
+ `data_volumes`: Include the instance's data volumes. - `active` - (Boolean) Indicates whether the plan is active. - `attach_user_tags` - (List) User tags to attach to each resource created by this plan. - `copy_user_tags` - (Boolean) Indicates whether to copy the source's user tags to the created resource. diff --git a/website/docs/d/is_snapshot.html.markdown b/website/docs/d/is_snapshot.html.markdown index fb9782077d..7ef79ed732 100644 --- a/website/docs/d/is_snapshot.html.markdown +++ b/website/docs/d/is_snapshot.html.markdown @@ -129,6 +129,18 @@ In addition to all argument reference list, you can access the following attribu - `operating_system` - (String) The globally unique name for the operating system included in this image. - `resource_type` - (String) The resource type. - `size` - (Integer) The size of this snapshot rounded up to the next gigabyte. +- `snapshot_consistency_group` - (List) The snapshot consistency group which created this snapshot. + + Nested scheme for `snapshot_consistency_group`: + - `crn` - (String) The CRN of this snapshot consistency group. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for the snapshot consistency group. + - `id` - (String) The unique identifier for the snapshot consistency group. + - `name` - (String) TThe name for the snapshot consistency group. The name is unique across all snapshot consistency groups in the region. + - `resource_type` - (String) The resource type. - `source_image` - (String) If present, the unique identifier for the image from which the data on this volume was most directly provisioned. - `source_snapshot` - (String) If present, the source snapshot this snapshot was created from. Nested scheme for `source_snapshot`: diff --git a/website/docs/d/is_snapshot_consistency_group.html.markdown b/website/docs/d/is_snapshot_consistency_group.html.markdown new file mode 100644 index 0000000000..43110ba9f8 --- /dev/null +++ b/website/docs/d/is_snapshot_consistency_group.html.markdown @@ -0,0 +1,90 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_snapshot_consistency_group" +description: |- + Get information about SnapshotConsistencyGroup +--- + +# ibm_is_snapshot_consistency_group + +Provides a read-only data source to retrieve information about a SnapshotConsistencyGroup. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +```terraform +data "ibm_is_snapshot_consistency_group" "is_snapshot_consistency_group" { + identifier = ibm_is_snapshot_consistency_group.is_snapshot_consistency_group.id +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `identifier` - (Optional, String) The snapshot consistency group identifier, `name` and `identifier` are mutually exclusive. +- `name` - (Optional, String) The name of the snapshot consistency group,`name` and `identifier` are mutually exclusive. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +- `id` - The unique identifier of the SnapshotConsistencyGroup. +- `backup_policy_plan` - (List) If present, the backup policy plan which created this snapshot consistency group. + + Nested schema for `backup_policy_plan`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted, and providessome supplementary information. + Nested schema for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this backup policy plan. + - `id` - (String) The unique identifier for this backup policy plan. + - `name` - (String) The name for this backup policy plan. The name is unique across all plans in the backup policy. + - `remote` - (List) If present, this property indicates that the resource associated with this referenceis remote and therefore may not be directly retrievable. + Nested schema for `remote`: + - `href` - (String) The URL for this region. + - `name` - (String) The globally unique name for this region. + - `resource_type` - (String) The resource type. + +- `created_at` - (String) The date and time that this snapshot consistency group was created. +- `crn` - (String) The CRN of this snapshot consistency group. +- `delete_snapshots_on_delete` - (Boolean) Indicates whether deleting the snapshot consistency group will also delete the snapshots in the group. +- `href` - (String) The URL for this snapshot consistency group. +- `lifecycle_state` - (String) The lifecycle state of this snapshot consistency group. +- `name` - (String) The name for this snapshot consistency group. The name is unique across all snapshot consistency groups in the region. +- `resource_group` - (List) The resource group for this snapshot consistency group. + + Nested schema for `resource_group`: + - `href` - (String) The URL for this resource group. + - `id` - (String) The unique identifier for this resource group. + - `name` - (String) The name for this resource group. + +- `resource_type` - (String) The resource type. +- `service_tags` - (List) The [service tags](https://cloud.ibm.com/apidocs/tagging#types-of-tags)[`is.instance:` prefix](https://cloud.ibm.com/docs/vpc?topic=vpc-snapshots-vpc-faqs) associated with this snapshot consistency group. +- `snapshots` - (List) The member snapshots that are data-consistent with respect to captured time. (may be[deleted](https://cloud.ibm.com/apidocs/vpc#deleted-resources)). + Nested schema for `snapshots`: + - `crn` - (String) The CRN of this snapshot. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted, and providessome supplementary information. + + Nested schema for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this snapshot. + - `id` - (String) The unique identifier for this snapshot. + - `name` - (String) The name for this snapshot. The name is unique across all snapshots in the region. + - `remote` - (List) If present, this property indicates that the resource associated with this referenceis remote and therefore may not be directly retrievable. + + Nested schema for `remote`: + - `href` - (String) The URL for this region. + - `name` - (String) The globally unique name for this region. + - `resource_type` - (String) The resource type. + diff --git a/website/docs/d/is_snapshot_consistency_groups.html.markdown b/website/docs/d/is_snapshot_consistency_groups.html.markdown new file mode 100644 index 0000000000..447cb1c4b1 --- /dev/null +++ b/website/docs/d/is_snapshot_consistency_groups.html.markdown @@ -0,0 +1,89 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_snapshot_consistency_groups" +description: |- + Get information about SnapshotConsistencyGroupCollection +--- + +# ibm_is_snapshot_consistency_groups + +Provides a read-only data source to retrieve information about a SnapshotConsistencyGroupCollection. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +```terraform +data "ibm_is_snapshot_consistency_groups" "is_snapshot_consistency_groups" { + name = "example-snapshot-consistency-group" +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `backup_policy_plan` - (Optional, String) Filters the collection to backup policy jobs with a `backup_policy_plan.id` property matching the specified identifier. +- `name` - (Optional, String) Filters the collection to resources with a `name` property matching the exact specified name. +- `resource_group` - (Optional, String) Filters the collection to resources with a `resource_group.id` property matching the specified identifier. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +- `id` - The unique identifier of the SnapshotConsistencyGroupCollection. +- `snapshot_consistency_groups` - (List) Collection of snapshot consistency groups. + + Nested schema for `snapshot_consistency_groups`: + - `backup_policy_plan` - (List) If present, the backup policy plan which created this snapshot consistency group. + Nested schema for `backup_policy_plan`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted, and providessome supplementary information. + + Nested schema for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this backup policy plan. + - `id` - (String) The unique identifier for this backup policy plan. + - `name` - (String) The name for this backup policy plan. The name is unique across all plans in the backup policy. + - `remote` - (List) If present, this property indicates that the resource associated with this referenceis remote and therefore may not be directly retrievable. + + Nested schema for `remote`: + - `href` - (String) The URL for this region. + - `name` - (String) The globally unique name for this region. + - `resource_type` - (String) The resource type. + - `created_at` - (String) The date and time that this snapshot consistency group was created. + - `crn` - (String) The CRN of this snapshot consistency group. + - `delete_snapshots_on_delete` - (Boolean) Indicates whether deleting the snapshot consistency group will also delete the snapshots in the group. + - `href` - (String) The URL for this snapshot consistency group. + - `id` - (String) The unique identifier for this snapshot consistency group. + - `lifecycle_state` - (String) The lifecycle state of this snapshot consistency group. + - `name` - (String) The name for this snapshot consistency group. The name is unique across all snapshot consistency groups in the region. + - `resource_group` - (List) The resource group identifier for this snapshot consistency group. + - `resource_type` - (String) The resource type. + - `service_tags` - (List) The [service tags](https://cloud.ibm.com/apidocs/tagging#types-of-tags)[`is.instance:` prefix](https://cloud.ibm.com/docs/vpc?topic=vpc-snapshots-vpc-faqs) associated with this snapshot consistency group. + - `snapshots` - (List) The member snapshots that are data-consistent with respect to captured time. (may be[deleted](https://cloud.ibm.com/apidocs/vpc#deleted-resources)). + + Nested schema for `snapshots`: + - `crn` - (String) The CRN of this snapshot. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted, and providessome supplementary information. + + Nested schema for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this snapshot. + - `id` - (String) The unique identifier for this snapshot. + - `name` - (String) The name for this snapshot. The name is unique across all snapshots in the region. + - `remote` - (List) If present, this property indicates that the resource associated with this referenceis remote and therefore may not be directly retrievable. + + Nested schema for `remote`: + - `href` - (String) The URL for this region. + - `name` - (String) The globally unique name for this region. + - `resource_type` - (String) The resource type. diff --git a/website/docs/d/is_snapshots.html.markdown b/website/docs/d/is_snapshots.html.markdown index 13f958492d..5c05317e70 100644 --- a/website/docs/d/is_snapshots.html.markdown +++ b/website/docs/d/is_snapshots.html.markdown @@ -37,8 +37,10 @@ Review the argument references that you can specify for your data source. - `resource_group` - (Optional, String) Filter snapshot collection by resource group id of the snapshot. - `source_image` - (Optional, String) Filter snapshot collection by source image of the snapshot. - `source_volume` - (Optional, String) Filter snapshot collection by source volume of the snapshot. -- `backup_policy_plan_tag` - Filters the collection to resources with the exact tag value. -- `backup_policy_plan_id` - Filters the collection to backup policy jobs with the backup plan with the specified identifier +- `backup_policy_plan_tag` - (Optional, String)Filters the collection to resources with the exact tag value. +- `backup_policy_plan_id` - (Optional, String)Filters the collection to backup policy jobs with the backup plan with the specified identifier +- `snapshot_consistency_group_id` - (Optional, String)Filters the collection to snapshots with snapshot consistency group with the specified identifier. +- `snapshot_consistency_group_crn` - (Optional, String)Filters the collection to snapshots with snapshot consistency group with the specified identifier. - `snapshot_copies_id` - Filters the collection to snapshots with copies with the specified identifier. - `snapshot_copies_name` - Filters the collection to snapshots with copies with the exact specified name. - `snapshot_copies_crn` - Filters the collection to snapshots with copies with the specified CRN. @@ -94,6 +96,18 @@ In addition to all argument reference list, you can access the following attribu - `operating_system` - (String) The globally unique name for the operating system included in this image. - `resource_type` - (String) The resource type. - `size` - (Integer) The size of this snapshot rounded up to the next gigabyte. + - `snapshot_consistency_group` - (List) The snapshot consistency group which created this snapshot. + + Nested scheme for `snapshot_consistency_group`: + - `crn` - (String) The CRN of this snapshot consistency group. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for the snapshot consistency group. + - `id` - (String) The unique identifier for the snapshot consistency group. + - `name` - (String) TThe name for the snapshot consistency group. The name is unique across all snapshot consistency groups in the region. + - `resource_type` - (String) The resource type. - `source_image` - (String) If present, the unique identifier for the image from which the data on this volume was most directly provisioned. - `source_snapshot` - (String) If present, the source snapshot this snapshot was created from. diff --git a/website/docs/r/is_backup_policy.html.markdown b/website/docs/r/is_backup_policy.html.markdown index 2f079c364b..aa0a61b83d 100644 --- a/website/docs/r/is_backup_policy.html.markdown +++ b/website/docs/r/is_backup_policy.html.markdown @@ -46,12 +46,16 @@ resource "ibm_is_backup_policy" "ent-baas-example1" { ## Argument Reference Review the argument reference that you can specify for your resource. +- `included_content` - (Optional, List) The included content for backups created using this policy. Allowed values are `boot_volume`, `data_volumes`. +~> **Note** + `boot_volume`: Include the instance's boot volume.
+ `data_volumes`: Include the instance's data volumes. - `match_resource_types` - (Optional, List) A resource type this backup policy applies to. Resources that have both a matching type and a matching user tag will be subject to the backup policy. The default value is `["volume"]`. - + ~> **Note** `match_resource_types` is deprecated. Please use `match_resource_type` instead. -- `match_resource_type` - (Optional, String) The resource type this backup policy will apply to. Resources that have both a matching type and a matching user tag will be subject to the backup policy. The default value is `["volume"]`. +- `match_resource_type` - (Optional, String) The resource type this backup policy will apply to. Resources that have both a matching type and a matching user tag will be subject to the backup policy. The default value is `["volume"]`. Allowed values are `volume`,`instance`. - `match_user_tags` - (Required, List) The user tags this backup policy applies to. Resources that have both a matching user tag and a matching type will be subject to the backup policy. - `name` - (Required, String) The user-defined name for this backup policy. Names must be unique within the region this backup policy resides in. - `resource_group` - (Optional, List) The resource group id, to use. If unspecified, the account's [default resource group](https://cloud.ibm.com/apidocs/resource-manager#introduction) is used. diff --git a/website/docs/r/is_snapshot.html.markdown b/website/docs/r/is_snapshot.html.markdown index 6c4fd4801c..59b901b598 100644 --- a/website/docs/r/is_snapshot.html.markdown +++ b/website/docs/r/is_snapshot.html.markdown @@ -159,6 +159,18 @@ In addition to all argument reference list, you can access the following attribu - `operating_system` - (String) The globally unique name for an Operating System included in this image. - `resource_type` - (String) The resource type. - `size` - (Integer) The size of this snapshot rounded up to the next gigabyte. +- `snapshot_consistency_group` - (List) The snapshot consistency group which created this snapshot. + + Nested scheme for `snapshot_consistency_group`: + - `crn` - (String) The CRN of this snapshot consistency group. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for the snapshot consistency group. + - `id` - (String) The unique identifier for the snapshot consistency group. + - `name` - (String) TThe name for the snapshot consistency group. The name is unique across all snapshot consistency groups in the region. + - `resource_type` - (String) The resource type. - `source_image` - (String) If present, the unique identifier for the image from which the data on this volume was most directly provisioned. - `source_snapshot` - (String) If present, the source snapshot this snapshot was created from. diff --git a/website/docs/r/is_snapshot_consistency_group.html.markdown b/website/docs/r/is_snapshot_consistency_group.html.markdown new file mode 100644 index 0000000000..18f944945a --- /dev/null +++ b/website/docs/r/is_snapshot_consistency_group.html.markdown @@ -0,0 +1,119 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_snapshot_consistency_group" +description: |- + Manages SnapshotConsistencyGroup. +--- + +# ibm_is_snapshot_consistency_group + +Create, update, and delete SnapshotConsistencyGroups with this resource. For more information, about snapshot consistency group, see [creating snapshot consistency group](https://cloud.ibm.com/docs/vpc?topic=vpc-snapshots-vpc-create). + +**Note** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +```terraform +resource "ibm_is_snapshot_consistency_group" "is_snapshot_consistency_group" { + delete_snapshots_on_delete = true + snapshots { + name = "example-snapshot" + source_volume = ibm_is_instance.testacc_instance.volume_attachments[0].volume_id + } + name = "example-snapshot-consistency-group" +} +``` + +## Argument Reference + +You can specify the following arguments for this resource. + +- `access_tags` - (Optional, List of Strings) A list of access management tags to attach to the bare metal server. + + ~> **Note:** + **•** You can attach only those access tags that already exists.
+ **•** For more information, about creating access tags, see [working with tags](https://cloud.ibm.com/docs/account?topic=account-tag&interface=ui#create-access-console).
+ **•** You must have the access listed in the [Granting users access to tag resources](https://cloud.ibm.com/docs/account?topic=account-access) for `access_tags`
+ **•** `access_tags` must be in the format `key:value`. +- `delete_snapshots_on_delete` - (Optional, Boolean) Indicates whether deleting the snapshot consistency group will also delete the snapshots in the group. +- `name` - (Optional, String) The name for this snapshot consistency group. The name is unique across all snapshot consistency groups in the region. +- `resource_group` - (Optional, Forces new resource, String) The resource group ID where the snapshot consistency group is to be created. +- `snapshots` - (Required, List) The member snapshots that are data-consistent with respect to captured time. (may be[deleted](https://cloud.ibm.com/apidocs/vpc#deleted-resources)). + + Nested schema for `snapshots`: + - `name` - (Optional, String) The name for this snapshot. + - `source_volume` - (Required, Forces new resource, String) The unique identifier for the volume for which snapshot is to be created. + - `tags`- (Optional, Array of Strings) A list of user tags that you want to add to your snapshot. (https://cloud.ibm.com/apidocs/tagging#types-of-tags) +- `tags`- (Optional, Array of Strings) A list of user tags that you want to add to your snapshot. (https://cloud.ibm.com/apidocs/tagging#types-of-tags) + + +## Attribute Reference + +After your resource is created, you can read values from the listed arguments and the following attributes. + +- `id` - The unique identifier of the SnapshotConsistencyGroup. +- `backup_policy_plan` - (List) If present, the backup policy plan which created this snapshot consistency group. + + Nested scheme for `backup_policy_plan`: + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this backup policy plan. + - `id` - (String) The unique identifier for this backup policy plan. + - `name` - (String) The unique user defined name for this backup policy plan. If unspecified, the name will be a hyphenated list of randomly selected words. + - `resource_type` - (String) The type of resource referenced. + - `remote` - (List) If present, this property indicates that the resource associated with this referenceis remote and therefore may not be directly retrievable. + + Nested schema for `remote`: + - `href` - (String) The URL for this region. + - `name` - (String) The globally unique name for this region. + +- `created_at` - (String) The date and time that this snapshot consistency group was created. +- `crn` - (String) The CRN of this snapshot consistency group. +- `href` - (String) The URL for this snapshot consistency group. +- `lifecycle_state` - (String) The lifecycle state of this snapshot consistency group. +- `resource_type` - (String) The resource type. +- `snapshots_reference` - (List) The member snapshots that are data-consistent with respect to captured time. (may be[deleted](https://cloud.ibm.com/apidocs/vpc#deleted-resources)). + + Nested scheme for `snapshots_reference`: + - `crn` - (String) The CRN of the source snapshot. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted and provides some supplementary information. + + Nested scheme for `deleted`: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for the source snapshot. + - `id` - (String) The unique identifier for the source snapshot. + - `name` - (String) The name for the source snapshot. The name is unique across all snapshots in the source snapshot's native region. + - `remote` - (List) If present, this property indicates the referenced resource is remote to this region,and identifies the native region + + Nested scheme for `remote`: + - `href` - (String) The URL for this region. + - `name` - (String) The globally unique name for this region. + - `resource_type` - (String) The resource type. +- `service_tags` - (List) The [service tags](https://cloud.ibm.com/apidocs/tagging#types-of-tags)[`is.instance:` prefix](https://cloud.ibm.com/docs/vpc?topic=vpc-snapshots-vpc-faqs) associated with this snapshot consistency group. + + +## Import + +You can import the `ibm_is_snapshot_consistency_group` resource by using `id`. The unique identifier for this snapshot consistency group. + +# Syntax +``` +$ terraform import ibm_is_snapshot_consistency_group.is_snapshot_consistency_group +``` + +# Example +``` +$ terraform import ibm_is_snapshot_consistency_group.is_snapshot_consistency_group r134-fa329f6b-0e36-433f-a3bb-0df632e79263 +``` From fa7de25e2721073cdb481fa4b656ef63e5c1d8f4 Mon Sep 17 00:00:00 2001 From: IDAN ADAR Date: Wed, 13 Dec 2023 13:57:14 +0200 Subject: [PATCH 12/14] Fix typo in filename --- ...as_secret.go => resource_ibm_sm_service_credentials_secret.go} | 0 ...test.go => resource_ibm_sm_service_credentials_secret_test.go} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename ibm/service/secretsmanager/{resource_ibm_sm_service_credentilas_secret.go => resource_ibm_sm_service_credentials_secret.go} (100%) rename ibm/service/secretsmanager/{resource_ibm_sm_service_credentilas_secret_test.go => resource_ibm_sm_service_credentials_secret_test.go} (100%) diff --git a/ibm/service/secretsmanager/resource_ibm_sm_service_credentilas_secret.go b/ibm/service/secretsmanager/resource_ibm_sm_service_credentials_secret.go similarity index 100% rename from ibm/service/secretsmanager/resource_ibm_sm_service_credentilas_secret.go rename to ibm/service/secretsmanager/resource_ibm_sm_service_credentials_secret.go diff --git a/ibm/service/secretsmanager/resource_ibm_sm_service_credentilas_secret_test.go b/ibm/service/secretsmanager/resource_ibm_sm_service_credentials_secret_test.go similarity index 100% rename from ibm/service/secretsmanager/resource_ibm_sm_service_credentilas_secret_test.go rename to ibm/service/secretsmanager/resource_ibm_sm_service_credentials_secret_test.go From fb2917e3a9830070d2c8c19dae9dac0b96238a1b Mon Sep 17 00:00:00 2001 From: hkantare Date: Wed, 13 Dec 2023 18:39:44 +0530 Subject: [PATCH 13/14] fix detect secret marking false positive --- .secrets.baseline | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/.secrets.baseline b/.secrets.baseline index dfa3b8db5b..f3e03c0153 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "go.mod|go.sum|.*.map|^.secrets.baseline$", "lines": null }, - "generated_at": "2023-12-11T16:26:19Z", + "generated_at": "2023-12-13T13:08:16Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -760,7 +760,7 @@ "hashed_secret": "731438016c5ab94431f61820f35e3ae5f8ad6004", "is_secret": false, "is_verified": false, - "line_number": 417, + "line_number": 426, "type": "Secret Keyword", "verified_result": null }, @@ -768,7 +768,7 @@ "hashed_secret": "12da2e35d6b50c902c014f1ab9e3032650368df7", "is_secret": false, "is_verified": false, - "line_number": 423, + "line_number": 432, "type": "Secret Keyword", "verified_result": null }, @@ -776,7 +776,7 @@ "hashed_secret": "813274ccae5b6b509379ab56982d862f7b5969b6", "is_secret": false, "is_verified": false, - "line_number": 1128, + "line_number": 1143, "type": "Base64 High Entropy String", "verified_result": null } @@ -786,7 +786,7 @@ "hashed_secret": "9184b0c38101bf24d78b2bb0d044deb1d33696fc", "is_secret": false, "is_verified": false, - "line_number": 131, + "line_number": 132, "type": "Secret Keyword", "verified_result": null }, @@ -794,7 +794,7 @@ "hashed_secret": "c427f185ddcb2440be9b77c8e45f1cd487a2e790", "is_secret": false, "is_verified": false, - "line_number": 1438, + "line_number": 1451, "type": "Base64 High Entropy String", "verified_result": null }, @@ -802,7 +802,7 @@ "hashed_secret": "1f7e33de15e22de9d2eaf502df284ed25ca40018", "is_secret": false, "is_verified": false, - "line_number": 1505, + "line_number": 1518, "type": "Secret Keyword", "verified_result": null }, @@ -810,7 +810,7 @@ "hashed_secret": "1f614c2eb6b3da22d89bd1b9fd47d7cb7c8fc670", "is_secret": false, "is_verified": false, - "line_number": 3298, + "line_number": 3338, "type": "Secret Keyword", "verified_result": null }, @@ -818,7 +818,7 @@ "hashed_secret": "7abfce65b8504403afc25c9790f358d513dfbcc6", "is_secret": false, "is_verified": false, - "line_number": 3311, + "line_number": 3351, "type": "Secret Keyword", "verified_result": null }, @@ -826,7 +826,7 @@ "hashed_secret": "0c2d85bf9a9b1579b16f220a4ea8c3d62b2e24b1", "is_secret": false, "is_verified": false, - "line_number": 3352, + "line_number": 3392, "type": "Secret Keyword", "verified_result": null } @@ -864,7 +864,7 @@ "hashed_secret": "c8b6f5ef11b9223ac35a5663975a466ebe7ebba9", "is_secret": false, "is_verified": false, - "line_number": 1806, + "line_number": 1838, "type": "Secret Keyword", "verified_result": null }, @@ -872,7 +872,7 @@ "hashed_secret": "8abf4899c01104241510ba87685ad4de76b0c437", "is_secret": false, "is_verified": false, - "line_number": 1812, + "line_number": 1844, "type": "Secret Keyword", "verified_result": null } @@ -3789,7 +3789,7 @@ "verified_result": null } ], - "ibm/service/secretsmanager/resource_ibm_sm_service_credentilas_secret.go": [ + "ibm/service/secretsmanager/resource_ibm_sm_service_credentials_secret.go": [ { "hashed_secret": "3046d9f6cfaaeea6eed9bb7a4ab010fe49b0cfd4", "is_secret": false, @@ -5010,7 +5010,7 @@ } ] }, - "version": "0.13.1+ibm.61.dss", + "version": "0.13.1+ibm.51.dss", "word_list": { "file": null, "hash": null From cb423dc702cc886a364f671bb85f2a705db39489 Mon Sep 17 00:00:00 2001 From: alex hemard Date: Thu, 14 Dec 2023 10:37:14 -0600 Subject: [PATCH 14/14] feat(Cloud Databases): Redis Database User RBAC support (#4982) --- .secrets.baseline | 50 +++- go.mod | 2 +- go.sum | 4 +- ibm/service/database/resource_ibm_database.go | 229 ++++++++++++++---- .../resource_ibm_database_redis_test.go | 22 +- .../database/resource_ibm_database_test.go | 90 ++++++- website/docs/r/database.html.markdown | 2 +- 7 files changed, 327 insertions(+), 72 deletions(-) diff --git a/.secrets.baseline b/.secrets.baseline index f3e03c0153..cb30966a3b 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "go.mod|go.sum|.*.map|^.secrets.baseline$", "lines": null }, - "generated_at": "2023-12-13T13:08:16Z", + "generated_at": "2023-12-14T01:01:48Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -2056,7 +2056,7 @@ "hashed_secret": "deab23f996709b4e3d14e5499d1cc2de677bfaa8", "is_secret": false, "is_verified": false, - "line_number": 1334, + "line_number": 1367, "type": "Secret Keyword", "verified_result": null }, @@ -2064,7 +2064,7 @@ "hashed_secret": "20a25bac21219ffff1904bde871ded4027eca2f8", "is_secret": false, "is_verified": false, - "line_number": 1923, + "line_number": 1957, "type": "Secret Keyword", "verified_result": null }, @@ -2072,7 +2072,7 @@ "hashed_secret": "b732fb611fd46a38e8667f9972e0cde777fbe37f", "is_secret": false, "is_verified": false, - "line_number": 1942, + "line_number": 1976, "type": "Secret Keyword", "verified_result": null }, @@ -2080,7 +2080,7 @@ "hashed_secret": "1f5e25be9b575e9f5d39c82dfd1d9f4d73f1975c", "is_secret": false, "is_verified": false, - "line_number": 2155, + "line_number": 2189, "type": "Secret Keyword", "verified_result": null } @@ -2224,7 +2224,15 @@ "hashed_secret": "2317aa72dafa0a07f05af47baa2e388f95dcf6f3", "is_secret": false, "is_verified": false, - "line_number": 272, + "line_number": 273, + "type": "Secret Keyword", + "verified_result": null + }, + { + "hashed_secret": "44cdfc3615970ada14420caaaa5c5745fca06002", + "is_secret": false, + "is_verified": false, + "line_number": 277, "type": "Secret Keyword", "verified_result": null } @@ -2234,7 +2242,7 @@ "hashed_secret": "c237978e1983e0caf1c3a84f1c2e72a7fb2981f2", "is_secret": false, "is_verified": false, - "line_number": 19, + "line_number": 20, "type": "Secret Keyword", "verified_result": null }, @@ -2242,7 +2250,7 @@ "hashed_secret": "d67007844d8f7fbc45ea3b27c4bea0bffafb53a0", "is_secret": false, "is_verified": false, - "line_number": 27, + "line_number": 28, "type": "Secret Keyword", "verified_result": null }, @@ -2250,7 +2258,7 @@ "hashed_secret": "279fb854eb9fa001b4629518a45c921cfad6d697", "is_secret": false, "is_verified": false, - "line_number": 35, + "line_number": 36, "type": "Secret Keyword", "verified_result": null }, @@ -2258,7 +2266,7 @@ "hashed_secret": "dad6fac3e5b6be7bb6f274970b4c50739a7e26ee", "is_secret": false, "is_verified": false, - "line_number": 59, + "line_number": 60, "type": "Secret Keyword", "verified_result": null }, @@ -2266,7 +2274,7 @@ "hashed_secret": "8cbbbfad0206e5953901f679b0d26d583c4f5ffe", "is_secret": false, "is_verified": false, - "line_number": 67, + "line_number": 68, "type": "Secret Keyword", "verified_result": null }, @@ -2274,7 +2282,7 @@ "hashed_secret": "f5ecb30890399c7b1d1781583478aaa9d0b0c89d", "is_secret": false, "is_verified": false, - "line_number": 91, + "line_number": 92, "type": "Secret Keyword", "verified_result": null }, @@ -2282,7 +2290,23 @@ "hashed_secret": "6da9eab371358a331c59a76d80a0ffcd589fe3c9", "is_secret": false, "is_verified": false, - "line_number": 101, + "line_number": 102, + "type": "Secret Keyword", + "verified_result": null + }, + { + "hashed_secret": "1f5e25be9b575e9f5d39c82dfd1d9f4d73f1975c", + "is_secret": false, + "is_verified": false, + "line_number": 163, + "type": "Secret Keyword", + "verified_result": null + }, + { + "hashed_secret": "e03932ac8a17ed1819fe161fd253bf323e0e3ec9", + "is_secret": false, + "is_verified": false, + "line_number": 172, "type": "Secret Keyword", "verified_result": null } diff --git a/go.mod b/go.mod index 638e7af953..4d51f3409c 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/IBM/apigateway-go-sdk v0.0.0-20210714141226-a5d5d49caaca github.com/IBM/appconfiguration-go-admin-sdk v0.3.0 github.com/IBM/appid-management-go-sdk v0.0.0-20210908164609-dd0e0eaf732f - github.com/IBM/cloud-databases-go-sdk v0.3.2 + github.com/IBM/cloud-databases-go-sdk v0.4.0 github.com/IBM/cloudant-go-sdk v0.0.43 github.com/IBM/code-engine-go-sdk v0.0.0-20231106200405-99e81b3ee752 github.com/IBM/container-registry-go-sdk v1.1.0 diff --git a/go.sum b/go.sum index dd2b86dde3..7f4070efcc 100644 --- a/go.sum +++ b/go.sum @@ -118,8 +118,8 @@ github.com/IBM/appconfiguration-go-admin-sdk v0.3.0 h1:OqFxnDxro0JiRwHBKytCcseY2 github.com/IBM/appconfiguration-go-admin-sdk v0.3.0/go.mod h1:xPxAYhr/uywUIDEo/JqWbkUdTryPdzRdYBfUpA5IjoE= github.com/IBM/appid-management-go-sdk v0.0.0-20210908164609-dd0e0eaf732f h1:4c1kqY4GqmkQ+tO03rneDb74Tv7BhTj8jDiDB1p8mdM= github.com/IBM/appid-management-go-sdk v0.0.0-20210908164609-dd0e0eaf732f/go.mod h1:d22kTYY7RYBWcQlZpqrSdshpB/lJ16viWS5Sbjtlc8s= -github.com/IBM/cloud-databases-go-sdk v0.3.2 h1:AUi7/xswqCwuXIlSyuXtDZJIm4d0ZicUBHhPrE9TnH0= -github.com/IBM/cloud-databases-go-sdk v0.3.2/go.mod h1:nCIVfeZnhBYIiwByT959dFP4VWUeNLxomDYy63tTC6M= +github.com/IBM/cloud-databases-go-sdk v0.4.0 h1:pmmMbJb/axolBEpCqq85idcZiimAOTacCyLUfAhXCqI= +github.com/IBM/cloud-databases-go-sdk v0.4.0/go.mod h1:nCIVfeZnhBYIiwByT959dFP4VWUeNLxomDYy63tTC6M= github.com/IBM/cloudant-go-sdk v0.0.43 h1:YxTy4RpAEezX32YIWnds76hrBREmO4u6IkBz1WylNuQ= github.com/IBM/cloudant-go-sdk v0.0.43/go.mod h1:WeYrJPaHTw19943ndWnVfwMIlZ5z0XUM2uEXNBrwZ1M= github.com/IBM/code-engine-go-sdk v0.0.0-20231106200405-99e81b3ee752 h1:S5NT0aKKUqd9hnIrPN/qUijKx9cZjJi3kfFpog0ByDA= diff --git a/ibm/service/database/resource_ibm_database.go b/ibm/service/database/resource_ibm_database.go index aa2808dcbe..8b70da011a 100644 --- a/ibm/service/database/resource_ibm_database.go +++ b/ibm/service/database/resource_ibm_database.go @@ -14,6 +14,7 @@ import ( "reflect" "regexp" "sort" + "strconv" "strings" "time" @@ -57,20 +58,53 @@ const ( ) const ( - redisRBACRoleRegexPattern = `([+-][a-z]+\s?)+` + redisRBACRoleRegexPattern = `[+-]@(?P[a-z]+)` ) type DatabaseUser struct { Username string Password string - Role string + Role *string Type string } +type databaseUserValidationError struct { + user *DatabaseUser + errs []error +} + +func (e *databaseUserValidationError) Error() string { + if len(e.errs) == 0 { + return "" + } + + var b []byte + for i, err := range e.errs { + if i > 0 { + b = append(b, '\n') + } + b = append(b, err.Error()...) + } + + return fmt.Sprintf("database user (%s) validation error:\n%s", e.user.Username, string(b)) +} + +func (e *databaseUserValidationError) Unwrap() []error { + return e.errs +} + type userChange struct { Old, New *DatabaseUser } +func redisRBACAllowedRoles() []string { + return []string{"all", "admin", "read", "write"} +} + +func opsManagerRoles() []string { + return []string{"group_read_only", "group_data_access_admin"} +} + func retry(f func() error) (err error) { attempts := 3 @@ -296,11 +330,10 @@ func ResourceIBMDatabaseInstance() *schema.Resource { ValidateFunc: validation.StringInSlice([]string{"database", "ops_manager", "read_only_replica"}, false), }, "role": { - Description: "User role. Only available for ops_manager user type.", - Type: schema.TypeString, - Optional: true, - Sensitive: false, - ValidateFunc: validation.StringInSlice([]string{"group_read_only", "group_data_access_admin"}, false), + Description: "User role. Only available for ops_manager user type and Redis 6.0 and above.", + Type: schema.TypeString, + Optional: true, + Sensitive: false, }, }, }, @@ -1330,23 +1363,23 @@ func resourceIBMDatabaseInstanceCreate(context context.Context, d *schema.Resour adminUser := deployment.AdminUsernames["database"] - user := &clouddatabasesv5.APasswordSettingUser{ + user := &clouddatabasesv5.UserUpdatePasswordSetting{ Password: &adminPassword, } - changeUserPasswordOptions := &clouddatabasesv5.ChangeUserPasswordOptions{ + updateUserOptions := &clouddatabasesv5.UpdateUserOptions{ ID: core.StringPtr(instanceID), UserType: core.StringPtr("database"), Username: core.StringPtr(adminUser), User: user, } - changeUserPasswordResponse, response, err := cloudDatabasesClient.ChangeUserPassword(changeUserPasswordOptions) + updateUserResponse, response, err := cloudDatabasesClient.UpdateUser(updateUserOptions) if err != nil { - return diag.FromErr(fmt.Errorf("[ERROR] ChangeUserPassword (%s) failed %s\n%s", *changeUserPasswordOptions.Username, err, response)) + return diag.FromErr(fmt.Errorf("[ERROR] UpdateUser (%s) failed %s\n%s", *updateUserOptions.Username, err, response)) } - taskID := *changeUserPasswordResponse.Task.ID + taskID := *updateUserResponse.Task.ID _, err = waitForDatabaseTaskComplete(taskID, d, meta, d.Timeout(schema.TimeoutCreate)) if err != nil { @@ -1919,23 +1952,24 @@ func resourceIBMDatabaseInstanceUpdate(context context.Context, d *schema.Resour if d.HasChange("adminpassword") { adminUser := d.Get("adminuser").(string) password := d.Get("adminpassword").(string) - user := &clouddatabasesv5.APasswordSettingUser{ + + user := &clouddatabasesv5.UserUpdatePasswordSetting{ Password: &password, } - changeUserPasswordOptions := &clouddatabasesv5.ChangeUserPasswordOptions{ + updateUserOptions := &clouddatabasesv5.UpdateUserOptions{ ID: core.StringPtr(instanceID), UserType: core.StringPtr("database"), Username: core.StringPtr(adminUser), User: user, } - changeUserPasswordResponse, response, err := cloudDatabasesClient.ChangeUserPassword(changeUserPasswordOptions) + updateUserResponse, response, err := cloudDatabasesClient.UpdateUser(updateUserOptions) if err != nil { - return diag.FromErr(fmt.Errorf("[ERROR] ChangeUserPassword (%s) failed %s\n%s", *changeUserPasswordOptions.Username, err, response)) + return diag.FromErr(fmt.Errorf("[ERROR] UpdateUser (%s) failed %s\n%s", *updateUserOptions.Username, err, response)) } - taskID := *changeUserPasswordResponse.Task.ID + taskID := *updateUserResponse.Task.ID _, err = waitForDatabaseTaskComplete(taskID, d, meta, d.Timeout(schema.TimeoutUpdate)) if err != nil { @@ -2813,6 +2847,28 @@ func validateGroupsDiff(_ context.Context, diff *schema.ResourceDiff, meta inter } func validateUsersDiff(_ context.Context, diff *schema.ResourceDiff, meta interface{}) (err error) { + service := diff.Get("service").(string) + + var versionStr string + var version int + + if _version, ok := diff.GetOk("version"); ok { + versionStr = _version.(string) + } + + if versionStr == "" { + // Latest Version + version = 0 + } else { + _v, err := strconv.ParseFloat(versionStr, 64) + + if err != nil { + return fmt.Errorf("invalid version: %s", versionStr) + } + + version = int(_v) + } + oldUsers, newUsers := diff.GetChange("users") userChanges := expandUserChanges(oldUsers.(*schema.Set).List(), newUsers.(*schema.Set).List()) @@ -2822,14 +2878,34 @@ func validateUsersDiff(_ context.Context, diff *schema.ResourceDiff, meta interf } if change.isCreate() || change.isUpdate() { - err = change.New.Validate() + err = change.New.ValidatePassword() + + if err != nil { + return err + } + + // TODO: Use Capability API + // RBAC roles supported for Redis 6.0 and above + if service == "databases-for-redis" && !(version > 0 && version < 6) { + err = change.New.ValidateRBACRole() + } else if service == "databases-for-mongodb" && change.New.Type == "ops_manager" { + err = change.New.ValidateOpsManagerRole() + } else { + if change.New.Role != nil { + if *change.New.Role != "" { + err = errors.New("role is not supported for this deployment or user type") + err = &databaseUserValidationError{user: change.New, errs: []error{err}} + } + } + } + if err != nil { return err } } } - return nil + return } func expandUsers(_users []interface{}) []*DatabaseUser { @@ -2845,10 +2921,17 @@ func expandUsers(_users []interface{}) []*DatabaseUser { user := DatabaseUser{ Username: tfUser["name"].(string), Password: tfUser["password"].(string), - Role: tfUser["role"].(string), Type: tfUser["type"].(string), } + // NOTE: cannot differentiate nil vs empty string + // https://github.com/hashicorp/terraform-plugin-sdk/issues/741 + if role, ok := tfUser["role"].(string); ok { + if tfUser["role"] != "" { + user.Role = &role + } + } + users = append(users, &user) } } @@ -2875,8 +2958,8 @@ func expandUserChanges(_oldUsers []interface{}, _newUsers []interface{}) (userCh userChanges = make([]*userChange, 0, len(userChangeMap)) - for _, user := range userChangeMap { - userChanges = append(userChanges, user) + for _, change := range userChangeMap { + userChanges = append(userChanges, change) } return userChanges @@ -2913,9 +2996,9 @@ func (u *DatabaseUser) Create(instanceID string, d *schema.ResourceData, meta in Password: core.StringPtr(u.Password), } - // User Role only for ops_manager user type - if u.Type == "ops_manager" && u.Role != "" { - userEntry.Role = core.StringPtr(u.Role) + // User Role only for ops_manager user type and Redis 6.0 and above + if u.Role != nil { + userEntry.Role = u.Role } createDatabaseUserOptions := &clouddatabasesv5.CreateDatabaseUserOptions{ @@ -2947,30 +3030,34 @@ func (u *DatabaseUser) Update(instanceID string, d *schema.ResourceData, meta in } // Attempt to update user password - passwordSettingUser := &clouddatabasesv5.APasswordSettingUser{ + user := &clouddatabasesv5.UserUpdate{ Password: core.StringPtr(u.Password), } - changeUserPasswordOptions := &clouddatabasesv5.ChangeUserPasswordOptions{ + if u.Role != nil { + user.Role = u.Role + } + + updateUserOptions := &clouddatabasesv5.UpdateUserOptions{ ID: &instanceID, UserType: core.StringPtr(u.Type), Username: core.StringPtr(u.Username), - User: passwordSettingUser, + User: user, } - changeUserPasswordResponse, response, err := cloudDatabasesClient.ChangeUserPassword(changeUserPasswordOptions) + updateUserResponse, response, err := cloudDatabasesClient.UpdateUser(updateUserOptions) // user was found but an error occurs while triggering task if err != nil || (response.StatusCode < 200 || response.StatusCode >= 300) { - return fmt.Errorf("[ERROR] ChangeUserPassword (%s) failed %w\n%s", *changeUserPasswordOptions.Username, err, response) + return fmt.Errorf("[ERROR] UpdateUser (%s) failed %w\n%s", *updateUserOptions.Username, err, response) } - taskID := *changeUserPasswordResponse.Task.ID + taskID := *updateUserResponse.Task.ID _, err = waitForDatabaseTaskComplete(taskID, d, meta, d.Timeout(schema.TimeoutUpdate)) if err != nil { return fmt.Errorf( - "[ERROR] Error waiting for database (%s) user (%s) create task to complete: %w", instanceID, *changeUserPasswordOptions.Username, err) + "[ERROR] Error waiting for database (%s) user (%s) create task to complete: %w", instanceID, *updateUserOptions.Username, err) } return nil @@ -3011,7 +3098,7 @@ func (u *DatabaseUser) isUpdatable() bool { return u.Type != "ops_manager" } -func (u *DatabaseUser) Validate() error { +func (u *DatabaseUser) ValidatePassword() (err error) { var errs []error var specialChars string @@ -3063,24 +3150,84 @@ func (u *DatabaseUser) Validate() error { } if len(errs) == 0 { - return nil + return } - var b []byte - for i, err := range errs { - if i > 0 { - b = append(b, '\n') + return &databaseUserValidationError{user: u, errs: errs} +} + +func (u *DatabaseUser) ValidateRBACRole() (err error) { + var errs []error + + if u.Role == nil || *u.Role == "" { + return + } + + if u.Type != "database" { + errs = append(errs, errors.New("role is only allowed for the database user")) + return &databaseUserValidationError{user: u, errs: errs} + } + + redisRBACCategoryRegex := regexp.MustCompile(redisRBACRoleRegexPattern) + redisRBACRoleRegex := regexp.MustCompile(fmt.Sprintf(`^(%s\s?)+$`, redisRBACRoleRegexPattern)) + + if !redisRBACRoleRegex.MatchString(*u.Role) { + errs = append(errs, errors.New("role must be in the format +@category or -@category")) + } + + matches := redisRBACCategoryRegex.FindAllStringSubmatch(*u.Role, -1) + + for _, match := range matches { + valid := false + role := match[1] + for _, allowed := range redisRBACAllowedRoles() { + if role == allowed { + valid = true + break + } } - b = append(b, err.Error()...) + + if !valid { + errs = append(errs, fmt.Errorf("role must contain only allowed categories: %s", strings.Join(redisRBACAllowedRoles()[:], ","))) + break + } + } + + if len(errs) == 0 { + return } - return fmt.Errorf("database user (%s) validation error:\n%w", u.Username, errors.New(string(b))) + return &databaseUserValidationError{user: u, errs: errs} +} + +func (u *DatabaseUser) ValidateOpsManagerRole() (err error) { + if u.Role == nil { + return + } + + if u.Type != "ops_manager" { + return + } + + if *u.Role == "" { + return + } + + for _, str := range opsManagerRoles() { + if *u.Role == str { + return + } + } + + err = fmt.Errorf("role must be a valid ops_manager role: %s", strings.Join(opsManagerRoles()[:], ",")) + + return &databaseUserValidationError{user: u, errs: []error{err}} } func DatabaseUserPasswordValidator(userType string) schema.SchemaValidateFunc { return func(i interface{}, k string) (warnings []string, errors []error) { user := &DatabaseUser{Username: "admin", Type: userType, Password: i.(string)} - err := user.Validate() + err := user.ValidatePassword() if err != nil { errors = append(errors, err) } diff --git a/ibm/service/database/resource_ibm_database_redis_test.go b/ibm/service/database/resource_ibm_database_redis_test.go index 64eec792a7..22366d31fe 100644 --- a/ibm/service/database/resource_ibm_database_redis_test.go +++ b/ibm/service/database/resource_ibm_database_redis_test.go @@ -70,14 +70,15 @@ func TestAccIBMDatabaseInstance_Redis_Basic(t *testing.T) { ), }, { - Config: testAccCheckIBMDatabaseInstanceRedisGroupMigration(databaseResourceGroup, testName), + Config: testAccCheckIBMDatabaseInstanceRedisUserRole(databaseResourceGroup, testName), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr(name, "name", testName), resource.TestCheckResourceAttr(name, "service", "databases-for-redis"), resource.TestCheckResourceAttr(name, "plan", "standard"), resource.TestCheckResourceAttr(name, "location", acc.Region()), - resource.TestCheckResourceAttr(name, "groups.0.memory.0.allocation_mb", "2048"), - resource.TestCheckResourceAttr(name, "groups.0.disk.0.allocation_mb", "4096"), + resource.TestCheckResourceAttr(name, "users.#", "1"), + resource.TestCheckResourceAttr(name, "users.0.name", "coolguy"), + resource.TestCheckResourceAttr(name, "users.0.role", "-@all +@read"), resource.TestCheckResourceAttr(name, "allowlist.#", "0"), ), }, @@ -257,7 +258,7 @@ func testAccCheckIBMDatabaseInstanceRedisReduced(databaseResourceGroup string, n `, databaseResourceGroup, name, acc.Region()) } -func testAccCheckIBMDatabaseInstanceRedisGroupMigration(databaseResourceGroup string, name string) string { +func testAccCheckIBMDatabaseInstanceRedisUserRole(databaseResourceGroup string, name string) string { return fmt.Sprintf(` data "ibm_resource_group" "test_acc" { is_default = true @@ -271,15 +272,10 @@ func testAccCheckIBMDatabaseInstanceRedisGroupMigration(databaseResourceGroup st location = "%[3]s" adminpassword = "password12345678" - group { - group_id = "member" - - memory { - allocation_mb = 1024 - } - disk { - allocation_mb = 2048 - } + users { + name = "coolguy" + password = "securepassword123" + role = "-@all +@read" } } `, databaseResourceGroup, name, acc.Region()) diff --git a/ibm/service/database/resource_ibm_database_test.go b/ibm/service/database/resource_ibm_database_test.go index d5633469a8..5e58458d58 100644 --- a/ibm/service/database/resource_ibm_database_test.go +++ b/ibm/service/database/resource_ibm_database_test.go @@ -4,6 +4,7 @@ package database import ( + "github.com/IBM/go-sdk-core/v5/core" "gotest.tools/assert" "testing" ) @@ -95,7 +96,7 @@ func TestValidateUserPassword(t *testing.T) { }, } for _, tc := range testcases { - err := tc.user.Validate() + err := tc.user.ValidatePassword() if tc.expectedError == "" { if err != nil { t.Errorf("TestValidateUserPassword: %q, %q unexpected error: %q", tc.user.Username, tc.user.Password, err.Error()) @@ -105,3 +106,90 @@ func TestValidateUserPassword(t *testing.T) { } } } + +func TestValidateRBACRole(t *testing.T) { + testcases := []struct { + user DatabaseUser + expectedError string + }{ + { + user: DatabaseUser{ + Username: "invalid_format", + Password: "", + Type: "database", + Role: core.StringPtr("+admin -all"), + }, + expectedError: "database user (invalid_format) validation error:\nrole must be in the format +@category or -@category", + }, + { + user: DatabaseUser{ + Username: "invalid_operation", + Password: "", + Type: "database", + Role: core.StringPtr("~@admin"), + }, + expectedError: "database user (invalid_operation) validation error:\nrole must be in the format +@category or -@category", + }, + { + user: DatabaseUser{ + Username: "invalid_category", + Password: "", + Type: "database", + Role: core.StringPtr("+@catfood -@dogfood"), + }, + expectedError: "database user (invalid_category) validation error:\nrole must contain only allowed categories: all,admin,read,write", + }, + { + user: DatabaseUser{ + Username: "one_bad_apple", + Password: "", + Type: "database", + Role: core.StringPtr("-@jazz +@read"), + }, + expectedError: "database user (one_bad_apple) validation error:\nrole must contain only allowed categories: all,admin,read,write", + }, + { + user: DatabaseUser{ + Username: "invalid_user_type", + Password: "", + Type: "ops_manager", + Role: core.StringPtr("+@all"), + }, + expectedError: "database user (invalid_user_type) validation error:\nrole is only allowed for the database user", + }, + { + user: DatabaseUser{ + Username: "valid", + Password: "", + Type: "database", + Role: core.StringPtr("-@all +@read"), + }, + expectedError: "", + }, + { + user: DatabaseUser{ + Username: "blank_role", + Password: "-@all +@read", + Type: "database", + Role: core.StringPtr(""), + }, + expectedError: "", + }, + } + for _, tc := range testcases { + err := tc.user.ValidateRBACRole() + if tc.expectedError == "" { + if err != nil { + t.Errorf("TestValidateRBACRole: %q, %q unexpected error: %q", tc.user.Username, *tc.user.Role, err.Error()) + } + } else { + var errMsg string + + if err != nil { + errMsg = err.Error() + } + + assert.Equal(t, tc.expectedError, errMsg) + } + } +} diff --git a/website/docs/r/database.html.markdown b/website/docs/r/database.html.markdown index b27f42deab..cfa9e61d86 100644 --- a/website/docs/r/database.html.markdown +++ b/website/docs/r/database.html.markdown @@ -684,7 +684,7 @@ Review the argument reference that you can specify for your resource. - `name` - (Required, String) The user name to add to the database instance. The user name must be in the range 5 - 32 characters. - `password` - (Required, String) The password for the user. Passwords must be between 15 and 32 characters in length and contain a letter and a number. Users with an `ops_manager` user type must have a password containing a special character `~!@#$%^&*()=+[]{}|;:,.<>/?_-` as well as a letter and a number. Other user types may only use special characters `-_`. - `type` - (Optional, String) The type for the user. Examples: `database`, `ops_manager`, `read_only_replica`. The default value is `database`. - - `role` - (Optional, String) The role for the user. Only available for `ops_manager` user type. Examples: `group_read_only`, `group_data_access_admin`. + - `role` - (Optional, String) The role for the user. Only available for `ops_manager` user type or Redis 6.0 and above. Example roles for `ops_manager`: `group_read_only`, `group_data_access_admin`. For, Redis 6.0 and above, `role` must be in Redis ACL syntax for adding and removing command categories i.e. `+@category` or `-@category`. Allowed command categories are `all`, `admin`, `read`, `write`. Example Redis `role`: `-@all +@read` - `allowlist` - (Optional, List of Objects) A list of allowed IP addresses for the database. Multiple blocks are allowed.