diff --git a/.secrets.baseline b/.secrets.baseline index 120fc954d0..614273b648 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "go.mod|go.sum|.*.map|^.secrets.baseline$", "lines": null }, - "generated_at": "2024-11-07T15:32:37Z", + "generated_at": "2024-11-27T08:58:01Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -526,7 +526,7 @@ "hashed_secret": "fd8bc0cb6ce2ef2fe2934f6d2d1ce1d648503740", "is_secret": false, "is_verified": false, - "line_number": 221, + "line_number": 256, "type": "Secret Keyword", "verified_result": null } @@ -796,7 +796,7 @@ "hashed_secret": "731438016c5ab94431f61820f35e3ae5f8ad6004", "is_secret": false, "is_verified": false, - "line_number": 509, + "line_number": 520, "type": "Secret Keyword", "verified_result": null }, @@ -804,7 +804,7 @@ "hashed_secret": "12da2e35d6b50c902c014f1ab9e3032650368df7", "is_secret": false, "is_verified": false, - "line_number": 515, + "line_number": 526, "type": "Secret Keyword", "verified_result": null }, @@ -812,7 +812,7 @@ "hashed_secret": "165722fe6dd0ec0afbeefb51c8258a177497956b", "is_secret": false, "is_verified": false, - "line_number": 771, + "line_number": 787, "type": "Hex High Entropy String", "verified_result": null }, @@ -820,7 +820,7 @@ "hashed_secret": "813274ccae5b6b509379ab56982d862f7b5969b6", "is_secret": false, "is_verified": false, - "line_number": 1379, + "line_number": 1412, "type": "Base64 High Entropy String", "verified_result": null } @@ -842,19 +842,11 @@ "type": "Base64 High Entropy String", "verified_result": null }, - { - "hashed_secret": "1f7e33de15e22de9d2eaf502df284ed25ca40018", - "is_secret": false, - "is_verified": false, - "line_number": 1581, - "type": "Secret Keyword", - "verified_result": null - }, { "hashed_secret": "1f614c2eb6b3da22d89bd1b9fd47d7cb7c8fc670", "is_secret": false, "is_verified": false, - "line_number": 3550, + "line_number": 3540, "type": "Secret Keyword", "verified_result": null }, @@ -862,7 +854,7 @@ "hashed_secret": "7abfce65b8504403afc25c9790f358d513dfbcc6", "is_secret": false, "is_verified": false, - "line_number": 3563, + "line_number": 3553, "type": "Secret Keyword", "verified_result": null }, @@ -870,7 +862,7 @@ "hashed_secret": "0c2d85bf9a9b1579b16f220a4ea8c3d62b2e24b1", "is_secret": false, "is_verified": false, - "line_number": 3604, + "line_number": 3594, "type": "Secret Keyword", "verified_result": null } @@ -898,7 +890,7 @@ "hashed_secret": "1a0334cfa65f4be58b9d914b8e96e9d9478bfbac", "is_secret": false, "is_verified": false, - "line_number": 3481, + "line_number": 3490, "type": "Secret Keyword", "verified_result": null } @@ -908,7 +900,7 @@ "hashed_secret": "c8b6f5ef11b9223ac35a5663975a466ebe7ebba9", "is_secret": false, "is_verified": false, - "line_number": 2258, + "line_number": 2296, "type": "Secret Keyword", "verified_result": null }, @@ -916,7 +908,7 @@ "hashed_secret": "8abf4899c01104241510ba87685ad4de76b0c437", "is_secret": false, "is_verified": false, - "line_number": 2264, + "line_number": 2302, "type": "Secret Keyword", "verified_result": null } @@ -1902,7 +1894,7 @@ "hashed_secret": "b732fb611fd46a38e8667f9972e0cde777fbe37f", "is_secret": false, "is_verified": false, - "line_number": 727, + "line_number": 737, "type": "Secret Keyword", "verified_result": null }, @@ -1910,7 +1902,7 @@ "hashed_secret": "3c956707ac29b4a200e47fceffa923341eed7e4f", "is_secret": false, "is_verified": false, - "line_number": 962, + "line_number": 972, "type": "Secret Keyword", "verified_result": null } @@ -2138,7 +2130,7 @@ "hashed_secret": "deab23f996709b4e3d14e5499d1cc2de677bfaa8", "is_secret": false, "is_verified": false, - "line_number": 1366, + "line_number": 1373, "type": "Secret Keyword", "verified_result": null }, @@ -2146,7 +2138,7 @@ "hashed_secret": "20a25bac21219ffff1904bde871ded4027eca2f8", "is_secret": false, "is_verified": false, - "line_number": 1960, + "line_number": 1974, "type": "Secret Keyword", "verified_result": null }, @@ -2154,7 +2146,7 @@ "hashed_secret": "b732fb611fd46a38e8667f9972e0cde777fbe37f", "is_secret": false, "is_verified": false, - "line_number": 1979, + "line_number": 1993, "type": "Secret Keyword", "verified_result": null } @@ -2164,7 +2156,7 @@ "hashed_secret": "2317aa72dafa0a07f05af47baa2e388f95dcf6f3", "is_secret": false, "is_verified": false, - "line_number": 190, + "line_number": 278, "type": "Secret Keyword", "verified_result": null } @@ -2174,7 +2166,7 @@ "hashed_secret": "2317aa72dafa0a07f05af47baa2e388f95dcf6f3", "is_secret": false, "is_verified": false, - "line_number": 771, + "line_number": 773, "type": "Secret Keyword", "verified_result": null } @@ -2250,7 +2242,7 @@ "hashed_secret": "2317aa72dafa0a07f05af47baa2e388f95dcf6f3", "is_secret": false, "is_verified": false, - "line_number": 145, + "line_number": 251, "type": "Secret Keyword", "verified_result": null } @@ -2260,7 +2252,7 @@ "hashed_secret": "728e83f156932be9b1dc48a5c3f7a3bfbeeb08ce", "is_secret": false, "is_verified": false, - "line_number": 472, + "line_number": 390, "type": "Secret Keyword", "verified_result": null }, @@ -2268,7 +2260,7 @@ "hashed_secret": "2317aa72dafa0a07f05af47baa2e388f95dcf6f3", "is_secret": false, "is_verified": false, - "line_number": 650, + "line_number": 568, "type": "Secret Keyword", "verified_result": null } @@ -2662,7 +2654,7 @@ "hashed_secret": "b02fa7fd7ca08b5dc86c2548e40f8a21171ef977", "is_secret": false, "is_verified": false, - "line_number": 276, + "line_number": 275, "type": "Secret Keyword", "verified_result": null }, @@ -2670,7 +2662,7 @@ "hashed_secret": "d4c3d66fd0c38547a3c7a4c6bdc29c36911bc030", "is_secret": false, "is_verified": false, - "line_number": 314, + "line_number": 313, "type": "Secret Keyword", "verified_result": null } @@ -2783,6 +2775,34 @@ "verified_result": null } ], + "ibm/service/iamidentity/data_source_ibm_iam_effective_account_settings.go": [ + { + "hashed_secret": "3046d9f6cfaaeea6eed9bb7a4ab010fe49b0cfd4", + "is_secret": false, + "is_verified": false, + "line_number": 368, + "type": "Secret Keyword", + "verified_result": null + }, + { + "hashed_secret": "2b5cb34f4edddfed903b2eb9f03c85cfe94fff22", + "is_secret": false, + "is_verified": false, + "line_number": 718, + "type": "Secret Keyword", + "verified_result": null + } + ], + "ibm/service/iamidentity/data_source_ibm_iam_effective_account_settings_test.go": [ + { + "hashed_secret": "469f62fa9e1c6afe62e8808180668934ee548e8f", + "is_secret": false, + "is_verified": false, + "line_number": 274, + "type": "Secret Keyword", + "verified_result": null + } + ], "ibm/service/iamidentity/resource_ibm_iam_account_settings.go": [ { "hashed_secret": "b939bb67ee5f5b13f7997dba58c31813ce8033f0", @@ -2922,7 +2942,7 @@ "hashed_secret": "b732fb611fd46a38e8667f9972e0cde777fbe37f", "is_secret": false, "is_verified": false, - "line_number": 1173, + "line_number": 1172, "type": "Secret Keyword", "verified_result": null } @@ -3823,6 +3843,26 @@ "verified_result": null } ], + "ibm/service/vpc/data_source_ibm_is_cluster_network_test.go": [ + { + "hashed_secret": "165722fe6dd0ec0afbeefb51c8258a177497956b", + "is_secret": false, + "is_verified": false, + "line_number": 197, + "type": "Hex High Entropy String", + "verified_result": null + } + ], + "ibm/service/vpc/data_source_ibm_is_cluster_networks_test.go": [ + { + "hashed_secret": "165722fe6dd0ec0afbeefb51c8258a177497956b", + "is_secret": false, + "is_verified": false, + "line_number": 308, + "type": "Hex High Entropy String", + "verified_result": null + } + ], "ibm/service/vpc/data_source_ibm_is_share_accessor_binding_test.go": [ { "hashed_secret": "cb76de39e0f3b6d952156908871c4b9c3daeae0e", @@ -3886,7 +3926,7 @@ "hashed_secret": "5fb0fa884132a8724a8d7cba55853737e442adbd", "is_secret": false, "is_verified": false, - "line_number": 119093, + "line_number": 119100, "type": "Secret Keyword", "verified_result": null }, @@ -3894,7 +3934,7 @@ "hashed_secret": "1e5c2f367f02e47a8c160cda1cd9d91decbac441", "is_secret": false, "is_verified": false, - "line_number": 151301, + "line_number": 151308, "type": "Secret Keyword", "verified_result": null } @@ -4349,6 +4389,16 @@ "verified_result": null } ], + "website/docs/r/db2_instance.html.markdown": [ + { + "hashed_secret": "91199272d5d6a574a51722ca6f3d1148edb1a0e7", + "is_secret": false, + "is_verified": false, + "line_number": 58, + "type": "Secret Keyword", + "verified_result": null + } + ], "website/docs/r/dl_gateway.html.markdown": [ { "hashed_secret": "622cc1dc32381e378d6cfb7301f03a71d93d2fe4", @@ -4515,12 +4565,22 @@ "verified_result": null } ], + "website/docs/r/is_cluster_network.html.markdown": [ + { + "hashed_secret": "165722fe6dd0ec0afbeefb51c8258a177497956b", + "is_secret": false, + "is_verified": false, + "line_number": 22, + "type": "Hex High Entropy String", + "verified_result": null + } + ], "website/docs/r/is_private_path_service_gateway_account_policy.html.markdown": [ { "hashed_secret": "165722fe6dd0ec0afbeefb51c8258a177497956b", "is_secret": false, "is_verified": false, - "line_number": 28, + "line_number": 25, "type": "Hex High Entropy String", "verified_result": null } @@ -4530,7 +4590,7 @@ "hashed_secret": "354fe46ea7cceda3813bfa9d7541d0922f1c45d0", "is_secret": false, "is_verified": false, - "line_number": 27, + "line_number": 24, "type": "Hex High Entropy String", "verified_result": null } @@ -4540,7 +4600,7 @@ "hashed_secret": "354fe46ea7cceda3813bfa9d7541d0922f1c45d0", "is_secret": false, "is_verified": false, - "line_number": 26, + "line_number": 23, "type": "Hex High Entropy String", "verified_result": null } diff --git a/CHANGELOG.md b/CHANGELOG.md index 9eb4659b58..3f34f090f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,76 @@ +# 1.72.0-beta0(Nov 27, 2024) +Features +* Support for Db2 SaaS + - **Resources** + - ibm_db2 + - **Datasources** + - ibm_db2 +* Support for IAM + - **Datasources** + - ibm_iam_effective_account_settings +* Support for MQaaS + - **Datasources** + - ibm_mqcloud_virtual_private_endpoint_gateway +* Support for VPC + - **Datasources** + - ibm_is_cluster_network + - ibm_is_cluster_networks + - ibm_is_cluster_network_interface + - ibm_is_cluster_network_interfaces + - ibm_is_cluster_network_profile + - ibm_is_cluster_network_profiles + - ibm_is_cluster_network_subnet + - ibm_is_cluster_network_subnets + - ibm_is_cluster_network_subnet_reserved_ip + - ibm_is_cluster_network_subnet_reserved_ips + - ibm_is_instance_cluster_network_attachment + - ibm_is_instance_cluster_network_attachments + - **Resources** + - ibm_is_cluster_network_interface + - ibm_is_cluster_network_subnet_reserved_ip + - ibm_is_cluster_network_subnet + - ibm_is_cluster_network + - ibm_is_instance_cluster_network_attachment + +Enhancements +* Add version validation ([5791](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5791)) +* Refactor shared-processor-pool resource ([5796](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5796)) +* Refactor Cloud Connection Network Attach ([5781](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5781)) +* Import a resource provisioned with key_protect_id and key_protect_instance attributes set ([5798](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5798)) +* enable commit while creating template/version ([5797](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5797)) +* ListClassicWorkers => ListAllWorkers ([5784](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5784)) +* chore: update mirroring example doc ([5767](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5767)) +* Update resource_instance.html.markdown ([5806](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5806)) +* fix(cloud-databases): Refactor tests Part 1 ([5810](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5810)) +* feat(BM-Reservations-Automatic-Attachment): Baremetal Server Reservations and Reservations Automatic Attachment ([5805](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5805)) +* Support enable secure-by-default ([5751](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5751)) +* Added support for volume_prototypes on ibm_is_instance resource ([5777](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5777)) +* ODF 4.16 terraform support ([5789](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5789)) +* Add Chenai to the doc ([5813](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5813)) +* ibm_pag_instance should force a new instance when parameters_json are updated ([5807](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5807)) + +BugFixes +* ICD: Promote read replicas ([5738](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5738)) +* docs(pps): Remove SA notes fpr private path service gateway feature ([5788](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5788)) +* Fix sap profile datasource warning ([5779](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5779)) +* fixed documents for is datasources ([5782](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5782)) +* fix: eventstreams sarama clientid ([5802](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5802)) +* fix(ibm_is_image): 404 error fix on datasource ([5769](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5769)) +* fix(ibm_is_share): 404 error fix on datasource ([5770](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5770)) +* fix(ibm_is_snapshot): 404 error fix on datasource ([5771](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5771)) +* vol fix for snapshot crn ([5815](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5815)) +* fix: adjust validation for Code Engine application scale_concurrency_target ([5792](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5792)) + + +# 1.71.3(Nov 26, 2024) +Bugfixes +* fix: HOT FIX to include properties from issue 5579 ([5818](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5818)) + +# 1.71.2(Nov 15, 2024) +Bugfixes +* Tags support config aggregator & Bug fix for settings api ([5783](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5783)) +* fix(partner center sell): fix patch nested fields ([5785](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5785)) + # 1.71.1(Nov 07, 2024) Bugfixes * Add error if image not found ([5730](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5730)) @@ -182,7 +255,7 @@ Bugfixes * Fix Config Aggregator ([5723](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5723)) * fix rule_group resource panic ([5744](https://github.com/IBM-Cloud/terraform-provider-ibm/pull/5744)) -# 1.71.0-beta0(Oct 20, 2024) + Features * Support Power System - **Resources** diff --git a/GNUmakefile b/GNUmakefile index 54c9ae11c0..a3f59882ad 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -34,7 +34,7 @@ test: fmtcheck xargs -t -n4 go test $(TESTARGS) -timeout=30s -parallel=4 testacc: fmtcheck - TF_ACC=1 go test $(TEST) -v $(TESTARGS) -timeout $(TEST_TIMEOUT) + TF_ACC=1 go test $(TEST) -v $(TESTARGS) -timeout $(TEST_TIMEOUT) testrace: fmtcheck TF_ACC= go test -race $(TEST) $(TESTARGS) diff --git a/examples/ibm-db2/README.md b/examples/ibm-db2/README.md new file mode 100644 index 0000000000..f8022a8290 --- /dev/null +++ b/examples/ibm-db2/README.md @@ -0,0 +1,49 @@ +# This example shows how to create an instance of IBM Db2 SaaS on IBM Cloud and configure connectivity from a VSI + +This sample provisions an IBM Db2 SaaS instance on IBM Cloud. + +## Costs + +This sample uses chargable services and **will** incur costs for the time the services are deployed. Execution of `terraform destroy` will result in deletion of all resources including the Db2 SaaS service instance. Billing for Db2 SaaS will terminate on the hour. + + +## Dependencies + +- User has IAM permissions to create and configure an IBM Db2 SaaS for IBM Cloud Instance in the resource group specified. + +## Configuration + +The terraform template requires you to provide values for the terraform variables. +Copy the file `variables.tfvars.example` as `variables.tfvars`. Provide appropriate values to the variables within the file. + +The following variables need to be set in the `terraform.tfvars` file before use: + +* `ibmcloud_api_key` - An API key for IBM Cloud services. If you don't have one already, go to https://cloud.ibm.com/iam/#/apikeys and create a new key. +* `region` - IBM Cloud region where your Db2 SaaS will be created. +* `resource_group` - Resource group within which Db2 SaaS will be created. + + +The example is deployed in the us-south region. The `region` parameter in main.tf must be set to the same region as the Db2 SaaS instance will be deployed in as defined by the `location` parameter on the ibm_db2 resource. + +## Outputs + +The composed connection string of Db2 SaaS Instance CRN. `crn:v1:bluemix:public:dashdb-for-transactions:us-south:a/60970f92286548d8a64cbb45bce39bc1:deae06ff-3966-4534-bfa0-4b42281e7cef::` + + +## Running the configuration +1. Initialize the terraform project to download the terraform providers and modules +```bash +$ terraform init +``` +2. Perform terraform plan with the variables. Run `terraform plan` to see the changes that will be applied to your account after you make any change to the terraform code. +```bash +$ terraform plan -var-file=./variables.tfvars +``` + +3. Perform terraform apply with the variables. Run `terraform apply` to apply the changes to the IBM Cloud after that will be applied to your account after you make any change to the terraform code. + +```bash +$ terraform apply -var-file=./variables.tfvars +``` + +Run `terraform destroy` to clean up and destroy all the resources created for the toolchain. diff --git a/examples/ibm-db2/main.tf b/examples/ibm-db2/main.tf new file mode 100644 index 0000000000..f4098ac82e --- /dev/null +++ b/examples/ibm-db2/main.tf @@ -0,0 +1,38 @@ +data "ibm_resource_group" "group" { + name = var.resource_group +} + +//Db2 SaaS Instance Creation +resource "ibm_db2" "db2_instance" { + name = "demo-db2" + service = "dashdb-for-transactions" + plan = "performance" + location = var.region + resource_group_id = data.ibm_resource_group.group.id + service_endpoints = "public-and-private" + instance_type = "bx2.4x16" + high_availability = "yes" + backup_location = "us" + + parameters_json = < 0.12 | + +## Providers + +| Name | Version | +|------|---------| +| ibm | 1.13.1 | diff --git a/examples/ibm-iam-identity-effective-account-settings/main.tf b/examples/ibm-iam-identity-effective-account-settings/main.tf new file mode 100644 index 0000000000..8ab985681d --- /dev/null +++ b/examples/ibm-iam-identity-effective-account-settings/main.tf @@ -0,0 +1,14 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key +} + +// Data source is not linked to a resource instance +// Uncomment if an existing data source instance exists +/* +// Create iam_effective_account_settings data source +data "ibm_iam_effective_account_settings" "iam_effective_account_settings_instance" { + account_id = var.iam_effective_account_settings_account_id + include_history = var.iam_effective_account_settings_include_history + resolve_user_mfa = var.iam_effective_account_settings_resolve_user_mfa +} +*/ diff --git a/examples/ibm-iam-identity-effective-account-settings/outputs.tf b/examples/ibm-iam-identity-effective-account-settings/outputs.tf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/ibm-iam-identity-effective-account-settings/variables.tf b/examples/ibm-iam-identity-effective-account-settings/variables.tf new file mode 100644 index 0000000000..e4d649688a --- /dev/null +++ b/examples/ibm-iam-identity-effective-account-settings/variables.tf @@ -0,0 +1,21 @@ +variable "ibmcloud_api_key" { + description = "IBM Cloud API key" + type = string +} + +// Data source arguments for iam_effective_account_settings +variable "iam_effective_account_settings_account_id" { + description = "Unique ID of the account." + type = string + default = "account_id" +} +variable "iam_effective_account_settings_include_history" { + description = "Defines if the entity history is included in the response." + type = bool + default = false +} +variable "iam_effective_account_settings_resolve_user_mfa" { + description = "Enrich MFA exemptions with user information." + type = bool + default = false +} diff --git a/examples/ibm-iam-identity-effective-account-settings/versions.tf b/examples/ibm-iam-identity-effective-account-settings/versions.tf new file mode 100644 index 0000000000..54c9d03e8d --- /dev/null +++ b/examples/ibm-iam-identity-effective-account-settings/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/examples/ibm-is-ng/main.tf b/examples/ibm-is-ng/main.tf index 4c34a38551..9c61f78672 100644 --- a/examples/ibm-is-ng/main.tf +++ b/examples/ibm-is-ng/main.tf @@ -1626,3 +1626,433 @@ data "ibm_is_reservations" "example" { data "ibm_is_reservation" "example" { identifier = ibm_is_reservation.example.id } + +// cluster examples +# ============================================================================================================= +variable prefix { + default = "test-cluster" +} +variable is_instances_resource_group_id { + default = "efhiorho4388yf348y83yvchrc083h0r30c" +} +variable region { + default = "us-east" +} +variable is_instances_name { + default = "test-vsi" +} +data "ibm_is_cluster_network_profile" "is_cluster_network_profile_instance" { + name = "h100" +} +data "ibm_is_cluster_network_profiles" "is_cluster_network_profiles_instance" { +} +# Create VPC +resource "ibm_is_vpc" "is_vpc" { + name = "${var.prefix}-vpc" +} +resource "ibm_is_vpc" "is_vpc2" { + name = "${var.prefix}-vpc2" +} + +# # # Create Subnet +resource "ibm_is_subnet" "is_subnet" { + name = "${var.prefix}-subnet" + vpc = ibm_is_vpc.is_vpc.id + total_ipv4_address_count = 64 + zone = "${var.region}-3" +} + +data ibm_is_instance_profile is_instance_profile_instance{ + name = "gx3d-160x1792x8h100" +} +data ibm_is_instance_profiles is_instance_profiles_instance{ +} +data "ibm_is_image" "is_image" { + name = "ibm-ubuntu-20-04-6-minimal-amd64-6" +} +resource "ibm_is_cluster_network" "is_cluster_network_instance" { + name = "${var.prefix}-cluster" + profile = "h100" + resource_group = var.is_instances_resource_group_id + subnet_prefixes { + cidr = "10.1.0.0/24" + } + vpc { + id = ibm_is_vpc.is_vpc.id + } + zone = "${var.region}-3" +} +resource "ibm_is_cluster_network" "is_cluster_network_instance" { + name = "${var.prefix}-cluster-updated" + profile = "h100" + subnet_prefixes { + cidr = "10.0.0.0/24" + } + vpc { + id = ibm_is_vpc.is_vpc.id + } + zone = ibm_is_subnet.is_subnet.zone +} +resource "ibm_is_cluster_network_subnet" "is_cluster_network_subnet_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + name = "${var.prefix}-cluster-subnet" + total_ipv4_address_count = 64 +} + +resource "ibm_is_cluster_network_subnet_reserved_ip" "is_cluster_network_subnet_reserved_ip_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + cluster_network_subnet_id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + address = "10.1.0.4" + name = "${var.prefix}-cluster-subnet-r-ip" +} + +resource "ibm_is_cluster_network_interface" "is_cluster_network_interface_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + name = "${var.prefix}-cluster-ni" + primary_ip { + id = ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance.cluster_network_subnet_reserved_ip_id + } + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } +} + +resource "ibm_is_instance_template" "is_instance_template" { + name = "${var.prefix}-cluster-it" + image = data.ibm_is_image.is_image.id + profile = "gx3d-160x1792x8h100" + primary_network_attachment { + name = "my-pna-it" + virtual_network_interface { + auto_delete = true + subnet = ibm_is_subnet.is_subnet.id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = ibm_is_cluster_network_interface.is_cluster_network_interface_instance.cluster_network_interface_id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = ibm_is_cluster_network_interface.is_cluster_network_interface_instance.cluster_network_interface_id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = ibm_is_cluster_network_interface.is_cluster_network_interface_instance.cluster_network_interface_id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = ibm_is_cluster_network_interface.is_cluster_network_interface_instance.cluster_network_interface_id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = ibm_is_cluster_network_interface.is_cluster_network_interface_instance.cluster_network_interface_id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = ibm_is_cluster_network_interface.is_cluster_network_interface_instance.cluster_network_interface_id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = ibm_is_cluster_network_interface.is_cluster_network_interface_instance.cluster_network_interface_id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = ibm_is_cluster_network_interface.is_cluster_network_interface_instance.cluster_network_interface_id + } + } + vpc = ibm_is_vpc.is_vpc.id + zone = ibm_is_subnet.is_subnet.zone + keys = [ibm_is_ssh_key.is_key.id] +} +resource "ibm_is_ssh_key" "is_key" { + name = "my-key" + public_key = file("~/.ssh/id_ed25519.pub") + type = "ed25519" +} + +resource "ibm_is_instance" "is_instance" { + name = "${var.prefix}-cluster-ins" + image = data.ibm_is_image.is_image.id + profile = "gx3d-160x1792x8h100" + primary_network_interface { + subnet = ibm_is_subnet.is_subnet.id + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-1" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-2" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-3" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-4" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-5" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-6" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-7" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-8" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + vpc = ibm_is_vpc.is_vpc.id + zone = ibm_is_subnet.is_subnet.zone + keys = [ibm_is_ssh_key.is_key.id] +} + +resource "ibm_is_instance_action" "is_instance_stop_before" { + action = "stop" + instance = ibm_is_instance.is_instance.id +} + +resource "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance" { + depends_on = [ibm_is_instance_action.is_instance_stop_before] + instance_id = ibm_is_instance.is_instance.id + before { + id = ibm_is_instance.is_instance.cluster_network_attachments.0.id + } + cluster_network_interface { + name = "my-cluster-network-interface" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + name = "cna-9" +} +resource "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance10" { + depends_on = [ibm_is_instance_action.is_instance_stop_before] + instance_id = ibm_is_instance.is_instance.id + before { + id = ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance.instance_cluster_network_attachment_id + } + cluster_network_interface { + name = "my-cluster-network-interface-10" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + name = "cna-10" +} +resource "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance11" { + depends_on = [ibm_is_instance_action.is_instance_stop_before] + instance_id = ibm_is_instance.is_instance.id + before { + id = ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance10.instance_cluster_network_attachment_id +} + cluster_network_interface { + name = "my-cluster-network-interface-11" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + name = "cna-11" +} +resource "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance12" { + depends_on = [ibm_is_instance_action.is_instance_stop_before] + instance_id = ibm_is_instance.is_instance.id + before { + id = ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance11.instance_cluster_network_attachment_id +} + cluster_network_interface { + name = "my-cluster-network-interface12" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + name = "cna-12" +} +resource "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance13" { + depends_on = [ibm_is_instance_action.is_instance_stop_before] + instance_id = ibm_is_instance.is_instance.id + before { + id = ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance12.instance_cluster_network_attachment_id + } + cluster_network_interface { + name = "my-cluster-network-interface13" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + name = "cna-13" +} +resource "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance14" { + depends_on = [ibm_is_instance_action.is_instance_stop_before] + instance_id = ibm_is_instance.is_instance.id + before { + id = ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance13.instance_cluster_network_attachment_id + } + cluster_network_interface { + name = "my-cluster-network-interface14" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + name = "cna-149" +} +resource "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance15" { + depends_on = [ibm_is_instance_action.is_instance_stop_before] + instance_id = ibm_is_instance.is_instance.id + before { + id = ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance14.instance_cluster_network_attachment_id + } + cluster_network_interface { + name = "my-cluster-network-interface15" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + name = "cna-15" +} +resource "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance16" { + depends_on = [ibm_is_instance_action.is_instance_stop_before] + instance_id = ibm_is_instance.is_instance.id + before { + id = ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance15.instance_cluster_network_attachment_id + } + cluster_network_interface { + name = "my-cluster-network-interface16" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + name = "cna-16" +} +resource "ibm_is_instance_action" "is_instance_start_after" { + # depends_on = [ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance16] + action = "start" + instance = ibm_is_instance.is_instance.id +} +resource "ibm_is_instance_action" "is_instance_stop_update" { + # depends_on = [ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance16] + action = "stop" + instance = ibm_is_instance.is_instance.id +} + +data "ibm_is_cluster_network" "is_cluster_network_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id +} +data "ibm_is_cluster_networks" "is_cluster_networks_instance" { +} + +data "ibm_is_cluster_network_interface" "is_cluster_network_interface_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + cluster_network_interface_id = ibm_is_cluster_network_interface.is_cluster_network_interface_instance.cluster_network_interface_id +} +data "ibm_is_cluster_network_interfaces" "is_cluster_network_interfaces_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id +} + +data "ibm_is_cluster_network_subnet" "is_cluster_network_subnet_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + cluster_network_subnet_id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id +} +data "ibm_is_cluster_network_subnets" "is_cluster_network_subnets_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id +} +data "ibm_is_cluster_network_subnet_reserved_ip" "is_cluster_network_subnet_reserved_ip_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + cluster_network_subnet_id =ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + cluster_network_subnet_reserved_ip_id = ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance.cluster_network_subnet_reserved_ip_id + +} +data "ibm_is_cluster_network_subnet_reserved_ips" "is_cluster_network_subnet_reserved_ips_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + cluster_network_subnet_id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id +} + +data "ibm_is_instance_template" "is_instance_template_instance" { + name = ibm_is_instance_template.is_instance_template.name +} +data "ibm_is_instance" "is_instance_instance" { + name = ibm_is_instance.is_instance.name +} +data "ibm_is_instances" "is_instances_instance" { +} +data "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance" { + instance_id = ibm_is_instance.is_instance.id + instance_cluster_network_attachment_id = ibm_is_instance.is_instance.cluster_network_attachments.0.id +} +data "ibm_is_instance_cluster_network_attachments" "is_instance_cluster_network_attachments_instance" { + instance_id = ibm_is_instance.is_instance.id +} +data "ibm_is_instances" "is_instances_instance" { + # resource_group_id = var.is_instances_resource_group_id + name = var.is_instances_name + # cluster_network_id = var.is_instances_cluster_network_id + # cluster_network_crn = var.is_instances_cluster_network_crn + # cluster_network_name = var.is_instances_cluster_network_name + # dedicated_host_id = var.is_instances_dedicated_host_id + # dedicated_host_crn = var.is_instances_dedicated_host_crn + # dedicated_host_name = var.is_instances_dedicated_host_name + # placement_group_id = var.is_instances_placement_group_id + # placement_group_crn = var.is_instances_placement_group_crn + # placement_group_name = var.is_instances_placement_group_name + # reservation_id = var.is_instances_reservation_id + # reservation_crn = var.is_instances_reservation_crn + # reservation_name = var.is_instances_reservation_name + # vpc_id = var.is_instances_vpc_id + # vpc_crn = var.is_instances_vpc_crn + # vpc_name = var.is_instances_vpc_name +} \ No newline at end of file diff --git a/examples/ibm-mqcloud/README.md b/examples/ibm-mqcloud/README.md index f2b1364e9c..815590f7f5 100644 --- a/examples/ibm-mqcloud/README.md +++ b/examples/ibm-mqcloud/README.md @@ -1,6 +1,6 @@ -# Examples for MQ on Cloud +# Examples for MQaaS -These examples illustrate how to use the resources and data sources associated with MQ on Cloud. +These examples illustrate how to use the resources and data sources associated with MQaaS. The following resources are supported: * ibm_mqcloud_queue_manager @@ -8,6 +8,7 @@ The following resources are supported: * ibm_mqcloud_user * ibm_mqcloud_keystore_certificate * ibm_mqcloud_truststore_certificate +* ibm_mqcloud_virtual_private_endpoint_gateway The following data sources are supported: * ibm_mqcloud_queue_manager_options @@ -17,6 +18,8 @@ The following data sources are supported: * ibm_mqcloud_user * ibm_mqcloud_truststore_certificate * ibm_mqcloud_keystore_certificate +* ibm_mqcloud_virtual_private_endpoint_gateways +* ibm_mqcloud_virtual_private_endpoint_gateway ## Usage @@ -30,7 +33,7 @@ $ terraform apply Run `terraform destroy` when you don't need these resources. -## MQ on Cloud resources +## MQaaS resources ### Resource: ibm_mqcloud_queue_manager @@ -50,7 +53,7 @@ resource "ibm_mqcloud_queue_manager" "mqcloud_queue_manager_instance" { | 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 | +| service_instance_guid | The GUID that uniquely identifies the MQaaS 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 | @@ -86,7 +89,7 @@ resource "ibm_mqcloud_application" "mqcloud_application_instance" { | 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 | +| service_instance_guid | The GUID that uniquely identifies the MQaaS service instance. | `string` | true | | name | The name of the application - conforming to MQ rules. | `string` | true | #### Outputs @@ -112,7 +115,7 @@ resource "ibm_mqcloud_user" "mqcloud_user_instance" { | 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 | +| service_instance_guid | The GUID that uniquely identifies the MQaaS service instance. | `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 | @@ -147,7 +150,7 @@ resource "ibm_mqcloud_keystore_certificate" "mqcloud_keystore_certificate_instan | 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 | +| service_instance_guid | The GUID that uniquely identifies the MQaaS service instance. | `string` | true | | queue_manager_id | The id of the queue manager to retrieve its full details. | `string` | true | | label | The label to use for the certificate to be uploaded. | `string` | true | | certificate_file | The filename and path of the certificate to be uploaded. | `base64-encoded string` | true | @@ -187,7 +190,7 @@ resource "ibm_mqcloud_truststore_certificate" "mqcloud_truststore_certificate_in | 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 | +| service_instance_guid | The GUID that uniquely identifies the MQaaS service instance. | `string` | true | | queue_manager_id | The id of the queue manager to retrieve its full details. | `string` | true | | label | The label to use for the certificate to be uploaded. | `string` | true | | certificate_file | The filename and path of the certificate to be uploaded. | `base64-encoded string` | true | @@ -208,7 +211,36 @@ resource "ibm_mqcloud_truststore_certificate" "mqcloud_truststore_certificate_in | href | The URL for this trust store certificate. | | certificate_id | Id of the certificate. | -## MQ on Cloud data sources +### Resource: ibm_mqcloud_virtual_private_endpoint_gateway + +```hcl +resource "ibm_mqcloud_virtual_private_endpoint_gateway" "mqcloud_virtual_private_endpoint_gateway_instance" { + service_instance_guid = var.mqcloud_virtual_private_endpoint_gateway_service_instance_guid + trusted_profile = var.mqcloud_virtual_private_endpoint_gateway_trusted_profile + name = var.mqcloud_virtual_private_endpoint_gateway_name + target_crn = var.mqcloud_virtual_private_endpoint_gateway_target_crn +} +``` + +#### Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| ibmcloud\_api\_key | IBM Cloud API key | `string` | true | +| service_instance_guid | The GUID that uniquely identifies the MQaaS service instance. | `string` | true | +| trusted_profile | The CRN of the trusted profile to assume for this request. | `string` | false | +| name | The name of the virtual private endpoint gateway, created by the user. | `string` | true | +| target_crn | The CRN of the reserved capacity service instance the user is trying to connect to. | `string` | true | + +#### Outputs + +| Name | Description | +|------|-------------| +| href | URL for the details of the virtual private endpoint gateway. | +| status | The lifecycle state of this virtual privage endpoint. | +| virtual_private_endpoint_gateway_guid | The ID of the virtual private endpoint gateway which was allocated on creation. | + +## MQaaS data sources ### Data source: ibm_mqcloud_queue_manager_options @@ -222,7 +254,7 @@ data "ibm_mqcloud_queue_manager_options" "mqcloud_queue_manager_options_instance | Name | Description | Type | Required | |------|-------------|------|---------| -| service_instance_guid | The GUID that uniquely identifies the MQ on Cloud service instance. | `string` | true | +| service_instance_guid | The GUID that uniquely identifies the MQaaS service instance. | `string` | true | #### Outputs @@ -246,7 +278,7 @@ data "ibm_mqcloud_queue_manager" "mqcloud_queue_manager_instance" { | Name | Description | Type | Required | |------|-------------|------|---------| -| service_instance_guid | The GUID that uniquely identifies the MQ on Cloud service instance. | `string` | true | +| service_instance_guid | The GUID that uniquely identifies the MQaaS service instance. | `string` | true | | name | A queue manager name conforming to MQ restrictions. | `string` | false | #### Outputs @@ -268,7 +300,7 @@ data "ibm_mqcloud_queue_manager_status" "mqcloud_queue_manager_status_instance" | Name | Description | Type | Required | |------|-------------|------|---------| -| service_instance_guid | The GUID that uniquely identifies the MQ on Cloud service instance. | `string` | true | +| service_instance_guid | The GUID that uniquely identifies the MQaaS service instance. | `string` | true | | queue_manager_id | The id of the queue manager to retrieve its full details. | `string` | true | #### Outputs @@ -290,7 +322,7 @@ data "ibm_mqcloud_application" "mqcloud_application_instance" { | Name | Description | Type | Required | |------|-------------|------|---------| -| service_instance_guid | The GUID that uniquely identifies the MQ on Cloud service instance. | `string` | true | +| service_instance_guid | The GUID that uniquely identifies the MQaaS service instance. | `string` | true | | name | The name of the application - conforming to MQ rules. | `string` | false | #### Outputs @@ -312,7 +344,7 @@ data "ibm_mqcloud_user" "mqcloud_user_instance" { | Name | Description | Type | Required | |------|-------------|------|---------| -| service_instance_guid | The GUID that uniquely identifies the MQ on Cloud service instance. | `string` | true | +| service_instance_guid | The GUID that uniquely identifies the MQaaS service instance. | `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` | false | #### Outputs @@ -335,7 +367,7 @@ data "ibm_mqcloud_truststore_certificate" "mqcloud_truststore_certificate_instan | Name | Description | Type | Required | |------|-------------|------|---------| -| service_instance_guid | The GUID that uniquely identifies the MQ on Cloud service instance. | `string` | true | +| service_instance_guid | The GUID that uniquely identifies the MQaaS service instance. | `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` | false | @@ -360,7 +392,7 @@ data "ibm_mqcloud_keystore_certificate" "mqcloud_keystore_certificate_instance" | Name | Description | Type | Required | |------|-------------|------|---------| -| service_instance_guid | The GUID that uniquely identifies the MQ on Cloud service instance. | `string` | true | +| service_instance_guid | The GUID that uniquely identifies the MQaaS service instance. | `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` | false | @@ -371,6 +403,57 @@ data "ibm_mqcloud_keystore_certificate" "mqcloud_keystore_certificate_instance" | total_count | The total count of key store certificates. | | key_store | The list of key store certificates. | +### Data source: ibm_mqcloud_virtual_private_endpoint_gateways + +```hcl +data "ibm_mqcloud_virtual_private_endpoint_gateways" "mqcloud_virtual_private_endpoint_gateways_instance" { + service_instance_guid = var.mqcloud_virtual_private_endpoint_gateways_service_instance_guid + trusted_profile = var.mqcloud_virtual_private_endpoint_gateways_trusted_profile + name = var.mqcloud_virtual_private_endpoint_gateways_name +} +``` + +#### Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| service_instance_guid | The GUID that uniquely identifies the MQaaS service instance. | `string` | true | +| trusted_profile | The CRN of the trusted profile to assume for this request. | `string` | false | +| name | The name of the virtual private endpoint gateway, created by the user. | `string` | false | + +#### Outputs + +| Name | Description | +|------|-------------| +| virtual_private_endpoint_gateways | List of virtual private endpoint gateways. | + +### Data source: ibm_mqcloud_virtual_private_endpoint_gateway + +```hcl +data "ibm_mqcloud_virtual_private_endpoint_gateway" "mqcloud_virtual_private_endpoint_gateway_instance" { + service_instance_guid = var.data_mqcloud_virtual_private_endpoint_gateway_service_instance_guid + virtual_private_endpoint_gateway_guid = var.data_mqcloud_virtual_private_endpoint_gateway_virtual_private_endpoint_gateway_guid + trusted_profile = var.data_mqcloud_virtual_private_endpoint_gateway_trusted_profile +} +``` + +#### Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| service_instance_guid | The GUID that uniquely identifies the MQaaS service instance. | `string` | true | +| virtual_private_endpoint_gateway_guid | The id of the virtual private endpoint gateway. | `string` | true | +| trusted_profile | The CRN of the trusted profile to assume for this request. | `string` | false | + +#### Outputs + +| Name | Description | +|------|-------------| +| href | URL for the details of the virtual private endpoint gateway. | +| name | The name of the virtual private endpoint gateway, created by the user. | +| target_crn | The CRN of the reserved capacity service instance the user is trying to connect to. | +| status | The lifecycle state of this virtual privage endpoint. | + ## Assumptions 1. TODO diff --git a/examples/ibm-mqcloud/main.tf b/examples/ibm-mqcloud/main.tf index ac259b2ffa..d5ebaa584d 100644 --- a/examples/ibm-mqcloud/main.tf +++ b/examples/ibm-mqcloud/main.tf @@ -5,24 +5,24 @@ provider "ibm" { // 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 + 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 + 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 + name = var.mqcloud_user_name + email = var.mqcloud_user_email } // Provision mqcloud_keystore_certificate resource instance @@ -32,6 +32,8 @@ resource "ibm_mqcloud_keystore_certificate" "mqcloud_keystore_certificate_instan label = var.mqcloud_keystore_certificate_label certificate_file = var.mqcloud_keystore_certificate_certificate_file + certificate_file = var.mqcloud_keystore_certificate_certificate_file + config { ams { channels { @@ -44,9 +46,17 @@ resource "ibm_mqcloud_keystore_certificate" "mqcloud_keystore_certificate_instan // 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 - certificate_file = var.mqcloud_truststore_certificate_certificate_file + queue_manager_id = var.mqcloud_truststore_certificate_queue_manager_id + label = var.mqcloud_truststore_certificate_label + certificate_file = var.mqcloud_truststore_certificate_certificate_file +} + +// Provision mqcloud_virtual_private_endpoint_gateway resource instance +resource "ibm_mqcloud_virtual_private_endpoint_gateway" "mqcloud_virtual_private_endpoint_gateway_instance" { + service_instance_guid = var.mqcloud_virtual_private_endpoint_gateway_service_instance_guid + trusted_profile = var.mqcloud_virtual_private_endpoint_gateway_trusted_profile + name = var.mqcloud_virtual_private_endpoint_gateway_name + target_crn = var.mqcloud_virtual_private_endpoint_gateway_target_crn } // Data source is not linked to a resource instance @@ -119,3 +129,25 @@ data "ibm_mqcloud_keystore_certificate" "mqcloud_keystore_certificate_instance" label = var.data_mqcloud_keystore_certificate_label } */ + +// Data source is not linked to a resource instance +// Uncomment if an existing data source instance exists +/* +// Create mqcloud_virtual_private_endpoint_gateways data source +data "ibm_mqcloud_virtual_private_endpoint_gateways" "mqcloud_virtual_private_endpoint_gateways_instance" { + service_instance_guid = var.mqcloud_virtual_private_endpoint_gateways_service_instance_guid + trusted_profile = var.mqcloud_virtual_private_endpoint_gateways_trusted_profile + name = var.mqcloud_virtual_private_endpoint_gateways_name +} +*/ + +// Data source is not linked to a resource instance +// Uncomment if an existing data source instance exists +/* +// Create mqcloud_virtual_private_endpoint_gateway data source +data "ibm_mqcloud_virtual_private_endpoint_gateway" "mqcloud_virtual_private_endpoint_gateway_instance" { + service_instance_guid = var.data_mqcloud_virtual_private_endpoint_gateway_service_instance_guid + virtual_private_endpoint_gateway_guid = var.data_mqcloud_virtual_private_endpoint_gateway_virtual_private_endpoint_gateway_guid + trusted_profile = var.data_mqcloud_virtual_private_endpoint_gateway_trusted_profile +} +*/ diff --git a/examples/ibm-mqcloud/outputs.tf b/examples/ibm-mqcloud/outputs.tf index ebd87da85e..029442f0c1 100644 --- a/examples/ibm-mqcloud/outputs.tf +++ b/examples/ibm-mqcloud/outputs.tf @@ -28,3 +28,9 @@ output "ibm_mqcloud_truststore_certificate" { value = ibm_mqcloud_truststore_certificate.mqcloud_truststore_certificate_instance description = "mqcloud_truststore_certificate resource instance" } +// This output allows mqcloud_virtual_private_endpoint_gateway data to be referenced by other resources and the terraform CLI +// Modify this output if only certain data should be exposed +output "ibm_mqcloud_virtual_private_endpoint_gateway" { + value = ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance + description = "mqcloud_virtual_private_endpoint_gateway resource instance" +} diff --git a/examples/ibm-mqcloud/variables.tf b/examples/ibm-mqcloud/variables.tf index 888e2fe82b..c371b06734 100644 --- a/examples/ibm-mqcloud/variables.tf +++ b/examples/ibm-mqcloud/variables.tf @@ -5,7 +5,7 @@ variable "ibmcloud_api_key" { // 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." + description = "The GUID that uniquely identifies the MQaaS service instance." type = string default = "Service Instance ID" } @@ -37,7 +37,7 @@ variable "mqcloud_queue_manager_version" { // Resource arguments for mqcloud_application variable "mqcloud_application_service_instance_guid" { - description = "The GUID that uniquely identifies the MQ on Cloud service instance." + description = "The GUID that uniquely identifies the MQaaS service instance." type = string default = "Service Instance ID" } @@ -49,7 +49,7 @@ variable "mqcloud_application_name" { // Resource arguments for mqcloud_user variable "mqcloud_user_service_instance_guid" { - description = "The GUID that uniquely identifies the MQ on Cloud service instance." + description = "The GUID that uniquely identifies the MQaaS service instance." type = string default = "Service Instance ID" } @@ -66,7 +66,7 @@ variable "mqcloud_user_email" { // 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." + description = "The GUID that uniquely identifies the MQaaS service instance." type = string default = "Service Instance ID" } @@ -85,6 +85,7 @@ variable "mqcloud_keystore_certificate_certificate_file" { type = string default = "SGVsbG8gd29ybGQ=" } + variable "mqcloud_keystore_certificate_config_ams_channel_name" { description = "A channel's information that is configured with this certificate." type = string @@ -93,7 +94,7 @@ variable "mqcloud_keystore_certificate_config_ams_channel_name" { // 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." + description = "The GUID that uniquely identifies the MQaaS service instance." type = string default = "Service Instance ID" } @@ -113,16 +114,38 @@ variable "mqcloud_truststore_certificate_certificate_file" { default = "SGVsbG8gd29ybGQ=" } +// Resource arguments for mqcloud_virtual_private_endpoint_gateway +variable "mqcloud_virtual_private_endpoint_gateway_service_instance_guid" { + description = "The GUID that uniquely identifies the MQaaS service instance." + type = string + default = "Service Instance ID" +} +variable "mqcloud_virtual_private_endpoint_gateway_trusted_profile" { + description = "The CRN of the trusted profile to assume for this request." + type = string + default = "CRN of Trusted Profile" +} +variable "mqcloud_virtual_private_endpoint_gateway_name" { + description = "The name of the virtual private endpoint gateway, created by the user." + type = string + default = "vpe-gateway1-to-vpe-gateway2" +} +variable "mqcloud_virtual_private_endpoint_gateway_target_crn" { + description = "The CRN of the reserved capacity service instance the user is trying to connect to." + type = string + default = "Virtual Private Endpoint CRN" +} + // Data source arguments for mqcloud_queue_manager_options variable "mqcloud_queue_manager_options_service_instance_guid" { - description = "The GUID that uniquely identifies the MQ on Cloud service instance." + description = "The GUID that uniquely identifies the MQaaS service instance." type = string default = "Service Instance ID" } // Data source arguments for mqcloud_queue_manager variable "data_mqcloud_queue_manager_service_instance_guid" { - description = "The GUID that uniquely identifies the MQ on Cloud service instance." + description = "The GUID that uniquely identifies the MQaaS service instance." type = string default = "Service Instance ID" } @@ -134,7 +157,7 @@ variable "data_mqcloud_queue_manager_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." + description = "The GUID that uniquely identifies the MQaaS service instance." type = string default = "Service Instance ID" } @@ -146,7 +169,7 @@ variable "mqcloud_queue_manager_status_queue_manager_id" { // Data source arguments for mqcloud_application variable "data_mqcloud_application_service_instance_guid" { - description = "The GUID that uniquely identifies the MQ on Cloud service instance." + description = "The GUID that uniquely identifies the MQaaS service instance." type = string default = "Service Instance ID" } @@ -158,7 +181,7 @@ variable "data_mqcloud_application_name" { // Data source arguments for mqcloud_user variable "data_mqcloud_user_service_instance_guid" { - description = "The GUID that uniquely identifies the MQ on Cloud service instance." + description = "The GUID that uniquely identifies the MQaaS service instance." type = string default = "Service Instance ID" } @@ -170,7 +193,7 @@ variable "data_mqcloud_user_name" { // Data source arguments for mqcloud_truststore_certificate variable "data_mqcloud_truststore_certificate_service_instance_guid" { - description = "The GUID that uniquely identifies the MQ on Cloud service instance." + description = "The GUID that uniquely identifies the MQaaS service instance." type = string default = "Service Instance ID" } @@ -187,7 +210,7 @@ variable "data_mqcloud_truststore_certificate_label" { // Data source arguments for mqcloud_keystore_certificate variable "data_mqcloud_keystore_certificate_service_instance_guid" { - description = "The GUID that uniquely identifies the MQ on Cloud service instance." + description = "The GUID that uniquely identifies the MQaaS service instance." type = string default = "Service Instance ID" } @@ -201,3 +224,37 @@ variable "data_mqcloud_keystore_certificate_label" { type = string default = "label" } + +// Data source arguments for mqcloud_virtual_private_endpoint_gateways +variable "mqcloud_virtual_private_endpoint_gateways_service_instance_guid" { + description = "The GUID that uniquely identifies the MQaaS service instance." + type = string + default = "a2b4d4bc-dadb-4637-bcec-9b7d1e723af8" +} +variable "mqcloud_virtual_private_endpoint_gateways_trusted_profile" { + description = "The CRN of the trusted profile to assume for this request." + type = string + default = "crn:v1:staging:public:mq-eude-stackname:eu-de:::endpoint:qm1.private.stackname.mq2.test.appdomain.cloud" +} +variable "mqcloud_virtual_private_endpoint_gateways_name" { + description = "The name of the virtual private endpoint gateway, created by the user." + type = string + default = "name" +} + +// Data source arguments for mqcloud_virtual_private_endpoint_gateway +variable "data_mqcloud_virtual_private_endpoint_gateway_service_instance_guid" { + description = "The GUID that uniquely identifies the MQaaS service instance." + type = string + default = "a2b4d4bc-dadb-4637-bcec-9b7d1e723af8" +} +variable "data_mqcloud_virtual_private_endpoint_gateway_virtual_private_endpoint_gateway_guid" { + description = "The id of the virtual private endpoint gateway." + type = string + default = "r010-ebab3c08-c9a8-40c4-8869-61c09ddf7b44" +} +variable "data_mqcloud_virtual_private_endpoint_gateway_trusted_profile" { + description = "The CRN of the trusted profile to assume for this request." + type = string + default = "crn:v1:staging:public:mq-eude-stackname:eu-de:::endpoint:qm1.private.stackname.mq2.test.appdomain.cloud" +} diff --git a/examples/openshift-data-foundation/addon/4.16.0/README.md b/examples/openshift-data-foundation/addon/4.16.0/README.md new file mode 100644 index 0000000000..70d41fe143 --- /dev/null +++ b/examples/openshift-data-foundation/addon/4.16.0/README.md @@ -0,0 +1,200 @@ +# Deploying and Managing Openshift Data Foundation + +This example shows how to deploy and manage the Openshift Data Foundation (ODF) on IBM Cloud VPC based RedHat Openshift cluster. Note this template is still in development, so please be advised before using in production. + +This sample configuration will deploy the ODF, scale and upgrade it using the "ibm_container_addons" and "kubernetes_manifest" from the ibm terraform provider and kubernetes provider respectively. + +For more information, about + +* ODF Deployment, see [Deploying OpenShift Data Foundation on VPC clusters](https://cloud.ibm.com/docs/openshift?topic=openshift-deploy-odf-vpc&interface=ui) +* ODF Management, see [Managing your OpenShift Data Foundation deployment](https://cloud.ibm.com/docs/openshift?topic=openshift-ocs-manage-deployment&interface=ui) + +#### Folder Structure + +```ini +├── openshift-data-foundation +│ ├── addon +│ │ ├── ibm-odf-addon +│ │ │ ├── main.tf +│ │ ├── ocscluster +│ │ │ ├── main.tf +│ │ ├── createaddon.sh +│ │ ├── createcrd.sh +│ │ ├── updatecrd.sh +│ │ ├── updateodf.sh +│ │ ├── deleteaddon.sh +│ │ ├── deletecrd.sh +│ │ ├── main.tf +│ │ ├── variables.tf +│ │ ├── schematics.tfvars +``` + +* `ibm-odf-addon` - This folder is used to deploy a specific Version of Openshift-Data-Foundation with the `odfDeploy` parameter set to false i.e the add-on is installed without the ocscluster using the IBM-Cloud Terraform Provider. +* `ocscluster` - This folder is used to deploy the `OcsCluster` CRD with the given parameters set in the `schematics.tfvars` file. +* `addon` - This folder contains scripts to create the CRD and deploy the ODF add-on on your cluster. `The main.tf` file contains the `null_resource` to internally call the above two folders, and perform the required actions. + +#### Note + +You do not have to change anything in the `ibm-odf-addon` and `ocscluster` folders. You just have to input the required parameters in the `schematics.tfvars` file under the `addon` folder, and run terraform. + +## Usage + +### Option 1 - Command Line Interface + +To run this example on your Terminal, first download this directory i.e `examples/openshift-data-foundation/` + +```bash +$ cd addon/4.16.0 +``` + +```bash +$ terraform init +$ terraform plan --var-file schematics.tfvars +$ terraform apply --var-file schematics.tfvars +``` + +Run `terraform destroy --var-file schematics.tfvars` when you don't need these resources. + +### Option 2 - IBM Cloud Schematics + +To Deploy & Manage the Openshift-Data-Foundation add-on using `IBM Cloud Schematics` please follow the below documentation + +https://cloud.ibm.com/docs/schematics?topic=schematics-get-started-terraform + +Please note you have to change the `terraform` keyword in the scripts to `terraform1.x` where `x` is the version of terraform you use in IBM Schematics, for example if you're using terraform version 1.3 in schematics make sure to change `terraform` -> `terraform1.3` in the .sh files. + +## Example usage + +### Deployment of ODF + +The default schematics.tfvars is given below, the user should just change the value of the parameters in accorandance to their requirment. + +```hcl +ibmcloud_api_key = "" # Enter your API Key +cluster = "" # Enter the Cluster ID +region = "us-south" # Enter the region + +# For add-on deployment +odfVersion = "4.16.0" + +# For CRD Creation and Management +autoDiscoverDevices = "false" +billingType = "advanced" +clusterEncryption = "false" +hpcsBaseUrl = null +hpcsEncryption = "false" +hpcsInstanceId = null +hpcsSecretName = null +hpcsServiceName = null +hpcsTokenUrl = null +ignoreNoobaa = "false" +numOfOsd = "1" +ocsUpgrade = "false" +osdDevicePaths = null +osdSize = "512Gi" +osdStorageClassName = "ibmc-vpc-block-metro-10iops-tier" +workerPools = null +workerNodes = null +encryptionInTransit = false +taintNodes = false +addSingleReplicaPool = false +prepareForDisasterRecovery = false +ignoreNoobaa = false +disableNoobaaLB = false +enableNFS = false +useCephRBDAsDefaultStorageClass = false +resourceProfile = "balanced" +``` + +### Scale-Up of ODF + +The following variables in the `schematics.tfvars` file can be edited + +* numOfOsd - To scale your storage +* workerNodes - To increase the number of Worker Nodes with ODF +* workerPools - To increase the number of Storage Nodes by adding more nodes using workerpool + +```hcl +# For CRD Management +numOfOsd = "1" -> "2" +workerNodes = null -> "worker_1_ID,worker_2_ID" +``` + +### Upgrade of ODF + +The following variables in the `schematics.tfvars` file should be changed in order to upgrade the ODF add-on and the Ocscluster CRD. + +* odfVersion - Specify the version you wish to upgrade to +* ocsUpgrade - Must be set to `true` to upgrade the CRD + +```hcl +# For ODF add-on upgrade +odfVersion = "4.16.0" -> "4.17.0" + +# For Ocscluster upgrade +ocsUpgrade = "false" -> "true" +``` + +## Examples + +* [ ODF Deployment & Management ](https://github.com/IBM-Cloud/terraform-provider-ibm/tree/master/examples/openshift-data-foundation/deployment) + + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | ~> 0.14.8 | + +## Providers + +| Name | Version | +|------|---------| +| ibm | latest | +| kubernetes | latest | + +## Inputs + +| Name | Description | Type | Required | Default +|------|-------------|------|----------|--------| +| ibmcloud_api_key | IBM Cloud API Key | `string` | yes | - +| cluster | Name of the cluster. | `string` | yes | - +| region | Region of the cluster | `string` | yes | - +| odfVersion | Version of the ODF add-on | `string` | yes | 4.12.0 +| osdSize | Enter the size for the storage devices that you want to provision for the Object Storage Daemon (OSD) pods | `string` | yes | 512Gi +| numOfOsd | The Number of OSD | `string` | yes | 1 +| osdStorageClassName | Enter the storage class to be used to provision block volumes for Object Storage Daemon (OSD) pods | `string` | yes | ibmc-vpc-block-metro-10iops-tier +| autoDiscoverDevices | Set to true if automatically discovering local disks | `string` | no | true +| billingType | Set to true if automatically discovering local disks | `string` | no | advanced +| clusterEncryption | To enable at-rest encryption of all disks in the storage cluster | `string` | no | false +| hpcsEncryption | Set to true to enable HPCS Encryption | `string` | no | false +| hpcsBaseUrl | The HPCS Base URL | `string` | no | null +| hpcsInstanceId | The HPCS Service ID | `string` | no | null +| hpcsSecretName | The HPCS secret name | `string` | no | null +| hpcsServiceName | The HPCS service name | `string` | no | null +| hpcsTokenUrl | The HPCS Token URL | `string` | no | null +| ignoreNoobaa | Set to true if you do not want MultiCloudGateway | `bool` | no | false +| ocsUpgrade | Set to true to upgrade Ocscluster | `string` | no | false +| osdDevicePaths | IDs of the disks to be used for OSD pods if using local disks or standard classic cluster | `string` | no | null +| workerPools | A list of the worker pools names where you want to deploy ODF. Either specify workerpool or workernodes to deploy ODF, if not specified ODF will deploy on all nodes | `string` | no | null +| workerNodes | Provide the names of the worker nodes on which to install ODF. Leave blank to install ODF on all worker nodes | `string` | no | null +| encryptionInTransit |To enable in-transit encryption. Enabling in-transit encryption does not affect the existing mapped or mounted volumes. After a volume is mapped/mounted, it retains the encryption settings that were used when it was initially mounted. To change the encryption settings for existing volumes, they must be remounted again one-by-one. | `bool` | no | false +| taintNodes | Specify true to taint the selected worker nodes so that only OpenShift Data Foundation pods can run on those nodes. Use this option only if you limit ODF to a subset of nodes in your cluster. | `bool` | no | false +| addSingleReplicaPool | Specify true to create a single replica pool without data replication, increasing the risk of data loss, data corruption, and potential system instability. | `bool` | no | false +| prepareForDisasterRecovery | Specify true to set up the storage system for disaster recovery service with the essential configurations in place. This allows seamless implementation of disaster recovery strategies for your workloads | `bool` | no | false +| disableNoobaaLB | Specify true to disable to NooBaa public load balancer. | `bool` | no | false +| enableNFS | Enabling this allows you to create exports using Network File System (NFS) that can then be accessed internally or externally from the OpenShift cluster. | `bool` | no | false +| useCephRBDAsDefaultStorageClass | Enable to set the Ceph RADOS block device (RBD) storage class as the default storage class during the deployment of OpenShift Data Foundation | `bool` | no | false +| resourceProfile | Provides an option to choose a resource profile based on the availability of resources during deployment. Choose between lean, balanced and performance. | `string` | yes | balanced + + +Refer - https://cloud.ibm.com/docs/openshift?topic=openshift-deploy-odf-vpc&interface=ui#odf-vpc-param-ref + +## Note + +* Users should only change the values of the variables within quotes, variables should be left untouched with the default values if they are not set. +* `workerNodes` takes a string containing comma separated values of the names of the worker nodes you wish to enable ODF on. +* On `terraform apply --var-file=schematics.tfvars`, the add-on is enabled and the custom resource is created. +* During ODF update, please do not tamper with the `ocsUpgrade` variable, just change the value to true within quotation, without changing the format of the variable. +* During the `Upgrade of Odf` scenario on IBM Schematics, please make sure to change the value of `ocsUpgrade` to `false` after. Locally this is automatically handled using `sed`. diff --git a/examples/openshift-data-foundation/addon/4.16.0/createaddon.sh b/examples/openshift-data-foundation/addon/4.16.0/createaddon.sh new file mode 100644 index 0000000000..68fb4a3223 --- /dev/null +++ b/examples/openshift-data-foundation/addon/4.16.0/createaddon.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -e + +WORKING_DIR=$(pwd) + +cp ${WORKING_DIR}/variables.tf ${WORKING_DIR}/ibm_odf_addon/variables.tf +cp ${WORKING_DIR}/schematics.tfvars ${WORKING_DIR}/ibm_odf_addon/schematics.tfvars +cd ${WORKING_DIR}/ibm_odf_addon +terraform init +terraform apply --auto-approve -var-file ${WORKING_DIR}/ibm_odf_addon/schematics.tfvars \ No newline at end of file diff --git a/examples/openshift-data-foundation/addon/4.16.0/createcrd.sh b/examples/openshift-data-foundation/addon/4.16.0/createcrd.sh new file mode 100644 index 0000000000..6a32158224 --- /dev/null +++ b/examples/openshift-data-foundation/addon/4.16.0/createcrd.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -e + +WORKING_DIR=$(pwd) + +cp ${WORKING_DIR}/variables.tf ${WORKING_DIR}/ocscluster/variables.tf +cp ${WORKING_DIR}/schematics.tfvars ${WORKING_DIR}/ocscluster/schematics.tfvars +cd ${WORKING_DIR}/ocscluster +terraform init +terraform apply --auto-approve -var-file ${WORKING_DIR}/ocscluster/schematics.tfvars \ No newline at end of file diff --git a/examples/openshift-data-foundation/addon/4.16.0/deleteaddon.sh b/examples/openshift-data-foundation/addon/4.16.0/deleteaddon.sh new file mode 100644 index 0000000000..e23f9be4f9 --- /dev/null +++ b/examples/openshift-data-foundation/addon/4.16.0/deleteaddon.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +set -e + +WORKING_DIR=$(pwd) + +cp ${WORKING_DIR}/variables.tf ${WORKING_DIR}/ibm_odf_addon/variables.tf +cp ${WORKING_DIR}/schematics.tfvars ${WORKING_DIR}/ibm_odf_addon/schematics.tfvars +cd ${WORKING_DIR}/ibm_odf_addon +terraform init +if [ -e ${WORKING_DIR}/ibm_odf_addon/terraform.tfstate ] +then + echo "ok" +else + terraform apply --auto-approve -var-file=${WORKING_DIR}/ibm_odf_addon/schematics.tfvars +fi +terraform destroy --auto-approve -var-file=${WORKING_DIR}/ibm_odf_addon/schematics.tfvars \ No newline at end of file diff --git a/examples/openshift-data-foundation/addon/4.16.0/deletecrd.sh b/examples/openshift-data-foundation/addon/4.16.0/deletecrd.sh new file mode 100644 index 0000000000..42127bc595 --- /dev/null +++ b/examples/openshift-data-foundation/addon/4.16.0/deletecrd.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +set -e + +WORKING_DIR=$(pwd) + +cp ${WORKING_DIR}/variables.tf ${WORKING_DIR}/ocscluster/variables.tf +cp ${WORKING_DIR}/schematics.tfvars ${WORKING_DIR}/ocscluster/schematics.tfvars +cd ${WORKING_DIR}/ocscluster +terraform init +if [ -e ${WORKING_DIR}/ocscluster/terraform.tfstate ] +then + echo "ok" +else + terraform import -var-file=${WORKING_DIR}/ocscluster/schematics.tfvars kubernetes_manifest.ocscluster_ocscluster_auto "apiVersion=ocs.ibm.io/v1,kind=OcsCluster,namespace=openshift-storage,name=ocscluster-auto" + terraform apply --auto-approve -var-file ${WORKING_DIR}/ocscluster/schematics.tfvars +fi + +terraform destroy --auto-approve -var-file=${WORKING_DIR}/ocscluster/schematics.tfvars \ No newline at end of file diff --git a/examples/openshift-data-foundation/addon/4.16.0/ibm_odf_addon/main.tf b/examples/openshift-data-foundation/addon/4.16.0/ibm_odf_addon/main.tf new file mode 100644 index 0000000000..2b35dd21d7 --- /dev/null +++ b/examples/openshift-data-foundation/addon/4.16.0/ibm_odf_addon/main.tf @@ -0,0 +1,33 @@ +terraform { + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = ">= 1.56.0" + } + } +} + +provider "ibm" { + region = var.region + ibmcloud_api_key = var.ibmcloud_api_key +} + + +resource "ibm_container_addons" "addons" { + + manage_all_addons = "false" + cluster = var.cluster + + addons { + + name = "openshift-data-foundation" + version = var.odfVersion + parameters_json = < "2" +workerNodes = null -> "worker_1_ID,worker_2_ID" +updateConfigRevision = true +workerPools = "workerpool_1" -> "workerpool_1,workerpool_2" +``` +In this example we set the `updateConfigRevision` parameter to true in order to update our storage assignment with the latest configuration revision i.e the OcsCluster CRD is updated with the latest changes. + +You could also use `updateAssignments` to directly update the storage configuration's assignments, but if you have a dependent `storage_assignment` resource, it's lifecycle will be affected. It it recommended to use this parameter when you've only defined the `storage_configuration` resource. + +### Upgrade of ODF + +**Step 1:** +Follow the [Satellite worker upgrade documentation](https://cloud.ibm.com/docs/satellite?topic=satellite-sat-storage-odf-update&interface=ui) step 1 to step 7 to perform worker upgrade. + +**Step 2:** +Follow the below steps to upgrade ODF to next version. +The following variables in the `input.tfvars` file should be changed in order to upgrade the ODF add-on and the Ocscluster CRD. + +* storageTemplateVersion - Specify the version you wish to upgrade to +* ocsUpgrade - Must be set to `true` to upgrade the CRD + +```hcl +# For ODF add-on upgrade +storageTemplateVersion = "4.14" -> "4.15" +ocsUpgrade = "false" -> "true" +``` + +Note this operation deletes the existing configuration and it's respective assignments, updates it to the next version and reassigns back to the previous clusters/groups. If used with a dependent assignment resource, it's lifecycle will be affected. It is recommended to perform this scenario when you've only defined the `storage_configuration` resource. + +## Examples + +* [ ODF Deployment & Management ](https://cloud.ibm.com/docs/satellite?topic=satellite-storage-odf-local&interface=ui) + + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | ~> 0.14.8 | + +## Providers + +| Name | Version | +|------|---------| +| ibm | latest | + +## Inputs + +| Name | Description | Type | Required | Default +|------|-------------|------|----------|--------| +| ibmcloud_api_key | IBM Cloud API Key | `string` | yes | - +| cluster | Name of the cluster. | `string` | yes | - +| region | Region of the cluster | `string` | yes | - +| storageTemplateVersion | Version of the Storage Template (odf-local) | `string` | yes | - +| storageTemplateName | Name of the Storage Template (odf-local)| `string` | yes | - +| numOfOsd | The Number of OSD | `string` | yes | 1 +| autoDiscoverDevices | Set to true if automatically discovering local disks | `string` | no | true +| billingType | Set to true if automatically discovering local disks | `string` | no | advanced +| performCleanup |Set to true if you want to perform complete cleanup of ODF on assignment deletion. | `bool` | yes | false +| clusterEncryption | To enable at-rest encryption of all disks in the storage cluster | `string` | no | false +| iamApiKey | Your IAM API key. | `string` | true | - +| kmsEncryption | Set to true to enable HPCS Encryption | `string` | yes | false +| kmsBaseUrl | The HPCS Base URL | `string` | no | null +| kmsInstanceId | The HPCS Service ID | `string` | no | null +| kmsSecretName | The HPCS secret name | `string` | no | null +| kmsInstanceName | The HPCS service name | `string` | no | null +| kmsTokenUrl | The HPCS Token URL | `string` | no | null +| ignoreNoobaa | Set to true if you do not want MultiCloudGateway | `bool` | no | false +| ocsUpgrade | Set to true to upgrade Ocscluster | `string` | no | false +| osdDevicePaths | IDs of the disks to be used for OSD pods if using local disks or standard classic cluster | `string` | no | null +| workerPools | Provide the names/ID of the workerpool on which to install ODF. Specify either workerpool or worker nodes to select storage nodes. If none of them specified, ODF will install on all workers | `string` | no | null +| workerNodes | Provide the names of the worker nodes on which to install ODF. | `string` | no | null +| encryptionInTransit |To enable in-transit encryption. Enabling in-transit encryption does not affect the existing mapped or mounted volumes. After a volume is mapped/mounted, it retains the encryption settings that were used when it was initially mounted. To change the encryption settings for existing volumes, they must be remounted again one-by-one. | `bool` | no | false +| taintNodes | Specify true to taint the selected worker nodes so that only OpenShift Data Foundation pods can run on those nodes. Use this option only if you limit ODF to a subset of nodes in your cluster. | `bool` | no | false +| addSingleReplicaPool | Specify true to create a single replica pool without data replication, increasing the risk of data loss, data corruption, and potential system instability. | `bool` | no | false +| prepareForDisasterRecovery | Specify true to set up the storage system for disaster recovery service with the essential configurations in place. This allows seamless implementation of disaster recovery strategies for your workloads | `bool` | no | false +| disableNoobaaLB | Specify true to disable to NooBaa public load balancer. | `bool` | no | false +| enableNFS | Enabling this allows you to create exports using Network File System (NFS) that can then be accessed internally or externally from the OpenShift cluster. | `bool` | no | false +| useCephRBDAsDefaultStorageClass | Enable to set the Ceph RADOS block device (RBD) storage class as the default storage class during the deployment of OpenShift Data Foundation | `bool` | no | false +| resourceProfile | Provides an option to choose a resource profile based on the availability of resources during deployment. Choose between lean, balanced and performance. | `string` | yes | balanced + +Refer - https://cloud.ibm.com/docs/satellite?topic=satellite-storage-odf-local&interface=ui#odf-local-4.14-parameters + +## Note + +* Users should only change the values of the variables within quotes, variables should be left untouched with the default values if they are not set. +* `workerPools` takes a string containing comma separated values of the names of the workerpool you wish to enable ODF on. Specify either workerpool or worker nodes to select storage nodes. If none of them specified, ODF will install on all workers +* `workerNodes` takes a string containing comma separated values of the names of the worker nodes you wish to enable ODF on. +* During ODF Storage Template Update, it is recommended to delete all terraform related assignments before handed, as their lifecycle will be affected, during update new storage assignments are made back internally with new UUIDs. diff --git a/examples/openshift-data-foundation/satellite/odf-local/4.16/input.tfvars b/examples/openshift-data-foundation/satellite/odf-local/4.16/input.tfvars new file mode 100644 index 0000000000..3111eb58ba --- /dev/null +++ b/examples/openshift-data-foundation/satellite/odf-local/4.16/input.tfvars @@ -0,0 +1,60 @@ +## DEFAULT VALUES ARE SET ## +## Please change according to your configuratiom ## + + +# Common for both storage configuration and assignment +ibmcloud_api_key = "" +location = "" #Location of your storage configuration and assignment +configName = "" #Name of your storage configuration +region = "" + + +#ODF Storage Configuration + +storageTemplateName = "odf-local" +storageTemplateVersion = "4.16" + +## User Parameters + +autoDiscoverDevices = "true" +osdDevicePaths = "" +billingType = "advanced" +clusterEncryption = "false" +kmsBaseUrl = null +kmsEncryption = "false" +kmsInstanceId = null +kmsInstanceName = null +kmsTokenUrl = null +ibmCosEndpoint = null +ibmCosLocation = null +ignoreNoobaa = false +numOfOsd = "1" +ocsUpgrade = "false" +workerPools = null +workerNodes = null +encryptionInTransit = false +disableNoobaaLB = false +performCleanup = false +taintNodes = false +addSingleReplicaPool = false +prepareForDisasterRecovery = false +enableNFS = false +useCephRBDAsDefaultStorageClass = false +resourceProfile = "balanced" + +## Secret Parameters +ibmCosAccessKey = null +ibmCosSecretKey = null +iamAPIKey = "" #Required +kmsApiKey = null +kmsRootKey = null + +#ODF Storage Assignment +assignmentName = "" +cluster = "" +updateConfigRevision = false + +## NOTE ## +# The following variables will cause issues to your storage assignment lifecycle, so please use only with a storage configuration resource. +deleteAssignments = false +updateAssignments = false diff --git a/examples/openshift-data-foundation/satellite/odf-local/4.16/main.tf b/examples/openshift-data-foundation/satellite/odf-local/4.16/main.tf new file mode 100644 index 0000000000..f8bf9dd51b --- /dev/null +++ b/examples/openshift-data-foundation/satellite/odf-local/4.16/main.tf @@ -0,0 +1,64 @@ +terraform { + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = ">= 1.56.0" + } + } +} + +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.region +} + +resource "ibm_satellite_storage_configuration" "storage_configuration" { + location = var.location + config_name = var.configName + storage_template_name = var.storageTemplateName + storage_template_version = var.storageTemplateVersion + user_config_parameters = { + "auto-discover-devices" = var.autoDiscoverDevices, + "num-of-osd" = var.numOfOsd, + "osd-device-path" = var.osdDevicePaths, + "billing-type" = var.billingType, + "cluster-encryption" = var.clusterEncryption, + "ibm-cos-endpoint"= var.ibmCosEndpoint, + "ibm-cos-location"= var.ibmCosLocation, + "ignore-noobaa"= var.ignoreNoobaa, + "kms-base-url"= var.kmsBaseUrl, + "kms-encryption"= var.kmsEncryption, + "kms-instance-id"= var.kmsInstanceId, + "kms-instance-name"= var.kmsInstanceName, + "kms-token-url"= var.kmsTokenUrl, + "odf-upgrade"= var.ocsUpgrade, + "perform-cleanup"= var.performCleanup, + "disable-noobaa-LB"= var.disableNoobaaLB, + "encryption-intransit"= var.encryptionInTransit, + "worker-pools"=var.workerPools, + "worker-nodes"= var.workerNodes, + "add-single-replica-pool" = var.addSingleReplicaPool, + "taint-nodes" = var.taintNodes, + "prepare-for-disaster-recovery" = var.prepareForDisasterRecovery, + "resource-profile" = var.resourceProfile, + "use-ceph-rbd-as-default-storage-class" = var.useCephRBDAsDefaultStorageClass, + "enable-nfs" = var.enableNFS + } + user_secret_parameters = { + "iam-api-key"= var.iamAPIKey, + "ibm-cos-access-key" = var.ibmCosAccessKey, + "kms-root-key" = var.kmsRootKey, + "kms-api-key" = var.kmsApiKey + } + delete_assignments = var.deleteAssignments + update_assignments = var.updateAssignments +} + +resource "ibm_satellite_storage_assignment" "storage_assignment" { + assignment_name = var.assignmentName + cluster = var.cluster + controller = var.location + config = var.configName + depends_on = [ibm_satellite_storage_configuration.storage_configuration] + update_config_revision = var.updateConfigRevision +} diff --git a/examples/openshift-data-foundation/satellite/odf-local/4.16/variables.tf b/examples/openshift-data-foundation/satellite/odf-local/4.16/variables.tf new file mode 100644 index 0000000000..c96922ea01 --- /dev/null +++ b/examples/openshift-data-foundation/satellite/odf-local/4.16/variables.tf @@ -0,0 +1,269 @@ +variable "ibmcloud_api_key" { + type = string + description = "IBM Cloud API Key" +} + +variable "iamAPIKey" { + type = string + description = "Your IBM Cloud API Key" +} + +variable "location" { + type = string + description = "The satellite location where you want to create your configuration" +} + +variable "configName" { + type = string + description = "The name of your storage configuration" +} + +variable "storageTemplateName" { + type = string + description = "The storage template for your configuration." +} + +variable "storageTemplateVersion" { + type = string + description = "The version of the storage template." +} + +variable "region" { + type = string + description = "Enter Satellite Location Region" +} + +variable "odfVersion" { + type = string + default = "4.15.0" + description = "Provide the ODF Version you wish to install on your cluster" +} + +variable "numOfOsd" { +type = string +default = "1" +description = "Number of Osd" +} + +variable "osdDevicePaths" { +type = string +description = "IDs of the disks to be used for OSD pods if using local disks or standard classic cluster" +default = null +} + +variable "ocsUpgrade" { + type = string + default = "false" + description = "Set to true to upgrade Ocscluster" + +} + +variable "clusterEncryption" { + type = string + default = "false" + description = "Enable at-rest encryption of all disks in the storage cluster." +} + + +variable "billingType" { + type = string + default = "advanced" + description = "Choose between advanced and essentials" +} + +variable "ignoreNoobaa" { + type = bool + default = false + description = "Set to true if you do not want MultiCloudGateway" +} + +variable "performCleanup" { + type = bool + default = false + description = "Set to true if you want to perform cleanup during assignment deletion" +} + +variable "ibmCosEndpoint" { + type = string + default = null + description = "The IBM COS regional public endpoint" +} + +variable "ibmCosLocation" { + type = string + default = null + description = "The location constraint that you want to use when creating your bucket. For example us-east-standard." +} + +variable "ibmCosSecretKey" { + type = string + default = null + description = "Your IBM COS HMAC secret access key." +} + +variable "ibmCosAccessKey" { + type = string + default = null + description = "Your IBM COS HMAC access key ID." +} + +variable "kmsApiKey" { + type = string + default = null + description = "IAM API key to access the KMS instance. The API key that you provide must have at least Viewer access to the KMS instance." +} + +variable "kmsRootKey" { + type = string + default = null + description = "KMS root key of your instance." +} + +variable "osdSize" { + type = string + default = "250Gi" + description = "Enter the size for the storage devices that you want to provision for the Object Storage Daemon (OSD) pods." +} + +variable "osdStorageClassName" { + type = string + default = "ibmc-vpc-block-metro-10iops-tier" + description = "Enter the storage class to be used to provision block volumes for Object Storage Daemon (OSD) pods." + +} + +variable "autoDiscoverDevices" { + type = string + default = "false" + description = "Set to true if automatically discovering local disks" +} + +variable "kmsEncryption" { + type = string + default = "false" + description = "Set to true to enable HPCS Encryption" +} + +variable "kmsInstanceName" { + type = string + default = null + description = "Please provide HPCS service name" +} + +variable "kmsSecretName" { + type = string + default = null + description = "Please provide the HPCS secret name" +} + +variable "workerPools" { + type = string + default = null + description = "Provide the names/ID of the workerpool on which to install ODF. Specify either workerpool or worker nodes to select storage nodes. If none of them specified, ODF will install on all workers." +} + +variable "workerNodes" { + type = string + default = null + description = "Provide the names of the worker nodes on which to install ODF." +} + +variable "kmsInstanceId" { + type = string + default = null + description = "Please provide HPCS Service ID" +} + +variable "kmsBaseUrl" { + type = string + default = null + description = "Please provide HPCS Base URL" +} + +variable "kmsTokenUrl" { + type = string + default = null + description = "Please provide HPCS token URL" +} + +variable "encryptionInTransit" { + type = bool + default = false + description = "Enter true to enable in-transit encryption. Enabling in-transit encryption does not affect the existing mapped or mounted volumes. After a volume is mapped/mounted, it retains the encryption settings that were used when it was initially mounted. To change the encryption settings for existing volumes, they must be remounted again one-by-one." +} + +variable "disableNoobaaLB" { + type = bool + default = false + description = "Specify true to disable to NooBaa public load balancer." +} + +variable "cluster" { + type = string + description = "Cluster ID or Name you wish to assign your configuration to." +} + +variable "assignmentName" { + type = string + description = "Name of your storage assignment to a cluster" +} + +variable "updateConfigRevision" { + type = bool + default = false + description = "Set to true if you want to update the assignment with the latest configuration revision" +} + +variable "deleteAssignments" { + type = bool + default = false + description = "Set to true if you want to delete all the assignments of the configuration, during storage configuration destroy" +} + +variable "updateAssignments" { + type = bool + default = false + description = "Set to true if you want to update all the configuration's assignments with the latest revision" +} + +variable "taintNodes" { + type = bool + default = false + description = "Specify true to taint the selected worker nodes so that only OpenShift Data Foundation pods can run on those nodes. Use this option only if you limit ODF to a subset of nodes in your cluster." +} + +variable "addSingleReplicaPool" { + type = bool + default = false + description = "Specify true to create a single replica pool without data replication, increasing the risk of data loss, data corruption, and potential system instability." +} + +variable "prepareForDisasterRecovery" { + type = bool + default = false + description = "Specify true to set up the storage system for disaster recovery service with the essential configurations in place. This allows seamless implementation of disaster recovery strategies for your workloads." +} + +variable "enableNFS" { + + type = bool + default = false + description = "Enabling this allows you to create exports using Network File System (NFS) that can then be accessed internally or externally from the OpenShift cluster." + +} + +variable "useCephRBDAsDefaultStorageClass" { + + type = bool + default = false + description = "Enable to set the Ceph RADOS block device (RBD) storage class as the default storage class during the deployment of OpenShift Data Foundation" + +} + +variable "resourceProfile" { + + type = string + default = "balanced" + description = "Provides an option to choose a resource profile based on the availability of resources during deployment. Choose between lean, balanced and performance." + +} diff --git a/examples/openshift-data-foundation/satellite/odf-remote/4.16/README.md b/examples/openshift-data-foundation/satellite/odf-remote/4.16/README.md new file mode 100644 index 0000000000..742d0c469d --- /dev/null +++ b/examples/openshift-data-foundation/satellite/odf-remote/4.16/README.md @@ -0,0 +1,199 @@ +# Openshift Data Foundation - Remote Deployment + +This example shows how to deploy and manage the Openshift Data Foundation (ODF) on IBM Cloud Satellite based RedHat Openshift cluster. + +This sample configuration will deploy the ODF, scale and upgrade it using the "ibm_satellite_storage_configuration" and "ibm_satellite_storage_assignment" resources from the ibm terraform provider. + +For more information, about + +* ODF Deployment & Management on Satellite, see [OpenShift Data Foundation for remote devices](https://cloud.ibm.com/docs/satellite?topic=satellite-storage-odf-remote&interface=ui) + +## Usage + +### Option 1 - Command Line Interface + +To run this example on your Terminal, first download this directory i.e `examples/openshift-data-foundation/` + +```bash +$ cd satellite +``` + +```bash +$ terraform init +$ terraform plan --var-file input.tfvars +$ terraform apply --var-file input.tfvars +``` + +Run `terraform destroy --var-file input.tfvars` when you don't need these resources. + +### Option 2 - IBM Cloud Schematics + +To Deploy & Manage the Openshift-Data-Foundation add-on using `IBM Cloud Schematics` please follow the below documentation + +https://cloud.ibm.com/docs/schematics?topic=schematics-get-started-terraform + + +## Example usage + +### Deployment of ODF Storage Configuration and Assignment + +The default input.tfvars is given below, the user should just change the value of the parameters in accorandance to their requirment. + +```hcl +# Common for both storage configuration and assignment +ibmcloud_api_key = "" +location = "" #Location of your storage configuration and assignment +configName = "" #Name of your storage configuration +region = "" + + +#ODF Storage Configuration +storageTemplateName = "odf-remote" +storageTemplateVersion = "4.15" + +## User Parameters +billingType = "advanced" +clusterEncryption = "false" +kmsBaseUrl = null +kmsEncryption = "false" +kmsInstanceId = null +kmsInstanceName = null +kmsTokenUrl = null +ibmCosEndpoint = null +ibmCosLocation = null +ignoreNoobaa = false +numOfOsd = "1" +ocsUpgrade = "false" +osdSize = "512Gi" +osdStorageClassName = "ibmc-vpc-block-metro-5iops-tier" +workerPools = null +workerNodes = null +encryptionInTransit = false +disableNoobaaLB = false +performCleanup = false +taintNodes = false +addSingleReplicaPool = false +prepareForDisasterRecovery = false +enableNFS = false +useCephRBDAsDefaultStorageClass = false +resourceProfile = "balanced" + +## Secret Parameters +ibmCosAccessKey = null +ibmCosSecretKey = null +iamAPIKey = "" #Required +kmsApiKey = null +kmsRootKey = null + +#ODF Storage Assignment +assignmentName = "" +cluster = "" +updateConfigRevision = false + +## NOTE ## +# The following variables will cause issues to your storage assignment lifecycle, so please use only with a storage configuration resource. +deleteAssignments = false +updateAssignments = false +``` + +Please note with this deployment the storage configuration and it's respective storage assignment is created to your specific satellite cluster in this example, if you'd like more control over the resources you can split it up into different files. + +### Scale-Up of ODF + +The following variables in the `input.tfvars` file can be edited + +* numOfOsd - To scale your storage +* workerNodes - To increase the number of Worker Nodes with ODF +* workerPools - To increase the number of Worker Nodes with ODF by including new workerpools + +```hcl +numOfOsd = "1" -> "2" +workerNodes = null -> "worker_1_ID,worker_2_ID" +updateConfigRevision = true +workerPools = "workerpool_1" -> "workerpool_1,workerpool_2" +``` +In this example we set the `updateConfigRevision` parameter to true in order to update our storage assignment with the latest configuration revision i.e the OcsCluster CRD is updated with the latest changes. + +You could also use `updateAssignments` to directly update the storage configuration's assignments, but if you have a dependent `storage_assignment` resource, it's lifecycle will be affected. It it recommended to use this parameter when you've only defined the `storage_configuration` resource. + +### Upgrade of ODF + +**Step 1:** +Follow the [worker upgrade documentation](https://cloud.ibm.com/docs/satellite?topic=satellite-sat-storage-odf-update&interface=ui) from step 1 to step 7 to perform worker upgrade. + +**Step 2:** +Follow the below steps to upgrade ODF to next version. +The following variables in the `input.tfvars` file should be changed in order to upgrade the ODF add-on and the Ocscluster CRD. + +* storageTemplateVersion - Specify the version you wish to upgrade to +* ocsUpgrade - Must be set to `true` to upgrade the CRD + +```hcl +# For ODF add-on upgrade +storageTemplateVersion = "4.15" -> "4.16" +ocsUpgrade = "false" -> "true" +``` + +Note this operation deletes the existing configuration and it's respective assignments, updates it to the next version and reassigns back to the previous clusters/groups. If used with a dependent assignment resource, it's lifecycle will be affected. It is recommended to perform this scenario when you've only defined the `storage_configuration` resource. + +## Examples + +* [ ODF Deployment & Management ](https://cloud.ibm.com/docs/satellite?topic=satellite-storage-odf-remote&interface=ui) + + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | ~> 0.14.8 | + +## Providers + +| Name | Version | +|------|---------| +| ibm | latest | + +## Inputs + +| Name | Description | Type | Required | Default +|------|-------------|------|----------|--------| +| ibmcloud_api_key | IBM Cloud API Key | `string` | yes | - +| cluster | Name of the cluster. | `string` | yes | - +| region | Region of the cluster | `string` | yes | - +| storageTemplateVersion | Version of the Storage Template (odf-remote) | `string` | yes | - +| storageTemplateName | Name of the Storage Template (odf-remote)| `string` | yes | - +| osdSize | Enter the size for the storage devices that you want to provision for the Object Storage Daemon (OSD) pods | `string` | yes | 512Gi +| numOfOsd | The Number of OSD | `string` | yes | 1 +| osdStorageClassName | Enter the storage class to be used to provision block volumes for Object Storage Daemon (OSD) pods | `string` | yes | ibmc-vpc-block-metro-5iops-tier +| billingType | Set to true if automatically discovering local disks | `string` | no | advanced +| performCleanup |Set to true if you want to perform complete cleanup of ODF on assignment deletion. | `bool` | yes | false +| clusterEncryption | To enable at-rest encryption of all disks in the storage cluster | `string` | no | false +| iamApiKey | Your IAM API key. | `string` | true | - +| kmsEncryption | Set to true to enable HPCS Encryption | `string` | yes | false +| kmsBaseUrl | The HPCS Base URL | `string` | no | null +| kmsInstanceId | The HPCS Service ID | `string` | no | null +| kmsSecretName | The HPCS secret name | `string` | no | null +| kmsInstanceName | The HPCS service name | `string` | no | null +| kmsTokenUrl | The HPCS Token URL | `string` | no | null +| ignoreNoobaa | Set to true if you do not want MultiCloudGateway | `bool` | no | false +| ocsUpgrade | Set to true to upgrade Ocscluster | `string` | no | false +| workerPools | Provide the names/ID of the workerpool on which to install ODF. Specify either workerpool or worker nodes to select storage nodes. If none of them specified, ODF will install on all workers | `string` | no | null +| workerNodes | Provide the names of the worker nodes on which to install ODF. Leave blank to install ODF on all worker nodes | `string` | no | null +| encryptionInTransit |To enable in-transit encryption. Enabling in-transit encryption does not affect the existing mapped or mounted volumes. After a volume is mapped/mounted, it retains the encryption settings that were used when it was initially mounted. To change the encryption settings for existing volumes, they must be remounted again one-by-one. | `bool` | no | false +| taintNodes | Specify true to taint the selected worker nodes so that only OpenShift Data Foundation pods can run on those nodes. Use this option only if you limit ODF to a subset of nodes in your cluster. | `bool` | no | false +| addSingleReplicaPool | Specify true to create a single replica pool without data replication, increasing the risk of data loss, data corruption, and potential system instability. | `bool` | no | false +| prepareForDisasterRecovery | Specify true to set up the storage system for disaster recovery service with the essential configurations in place. This allows seamless implementation of disaster recovery strategies for your workloads | `bool` | no | false +| disableNoobaaLB | Specify true to disable to NooBaa public load balancer. | `bool` | no | false +| enableNFS | Enabling this allows you to create exports using Network File System (NFS) that can then be accessed internally or externally from the OpenShift cluster. | `bool` | no | false +| useCephRBDAsDefaultStorageClass | Enable to set the Ceph RADOS block device (RBD) storage class as the default storage class during the deployment of OpenShift Data Foundation | `bool` | no | false +| resourceProfile | Provides an option to choose a resource profile based on the availability of resources during deployment. Choose between lean, balanced and performance. | `string` | yes | balanced + +Refer - https://cloud.ibm.com/docs/satellite?topic=satellite-storage-odf-remote&interface=ui#odf-remote-4.14-parameters + +## Note + +* Users should only change the values of the variables within quotes, variables should be left untouched with the default values if they are not set. +* `workerPools` takes a string containing comma separated values of the names of the workerpool you wish to enable ODF on. Specify either workerpool or worker nodes to select storage nodes. If none of them specified, ODF will install on all workers +* `workerNodes` takes a string containing comma separated values of the names of the worker nodes you wish to enable ODF on. +* During ODF Storage Template Update, it is recommended to delete all terraform related assignments before handed, as their lifecycle will be affected, during update new storage assignments are made back internally with new UUIDs. diff --git a/examples/openshift-data-foundation/satellite/odf-remote/4.16/input.tfvars b/examples/openshift-data-foundation/satellite/odf-remote/4.16/input.tfvars new file mode 100644 index 0000000000..9dd9e70f0d --- /dev/null +++ b/examples/openshift-data-foundation/satellite/odf-remote/4.16/input.tfvars @@ -0,0 +1,60 @@ +## DEFAULT VALUES ARE SET ## +## Please change according to your configuratiom ## + + +# Common for both storage configuration and assignment +ibmcloud_api_key = "" +location = "" #Location of your storage configuration and assignment +configName = "" #Name of your storage configuration +region = "" + + +#ODF Storage Configuration + +storageTemplateName = "odf-remote" +storageTemplateVersion = "4.16" + +## User Parameters + +billingType = "advanced" +clusterEncryption = "false" +kmsBaseUrl = null +kmsEncryption = "false" +kmsInstanceId = null +kmsInstanceName = null +kmsTokenUrl = null +ibmCosEndpoint = null +ibmCosLocation = null +ignoreNoobaa = false +numOfOsd = "1" +ocsUpgrade = "false" +osdSize = "512Gi" +osdStorageClassName = "ibmc-vpc-block-metro-5iops-tier" +workerPools = null +workerNodes = null +encryptionInTransit = false +disableNoobaaLB = false +performCleanup = false +taintNodes = false +addSingleReplicaPool = false +prepareForDisasterRecovery = false +enableNFS = false +useCephRBDAsDefaultStorageClass = false +resourceProfile = "balanced" + +## Secret Parameters +ibmCosAccessKey = null +ibmCosSecretKey = null +iamAPIKey = "" #Required +kmsApiKey = null +kmsRootKey = null + +#ODF Storage Assignment +assignmentName = "" +cluster = "" +updateConfigRevision = false + +## NOTE ## +# The following variables will cause issues to your storage assignment lifecycle, so please use only with a storage configuration resource. +deleteAssignments = false +updateAssignments = false diff --git a/examples/openshift-data-foundation/satellite/odf-remote/4.16/main.tf b/examples/openshift-data-foundation/satellite/odf-remote/4.16/main.tf new file mode 100644 index 0000000000..169e9aab80 --- /dev/null +++ b/examples/openshift-data-foundation/satellite/odf-remote/4.16/main.tf @@ -0,0 +1,64 @@ +terraform { + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = ">= 1.56.0" + } + } +} + +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.region +} + +resource "ibm_satellite_storage_configuration" "storage_configuration" { + location = var.location + config_name = var.configName + storage_template_name = var.storageTemplateName + storage_template_version = var.storageTemplateVersion + user_config_parameters = { + "osd-size" = var.osdSize, + "num-of-osd" = var.numOfOsd, + "osd-storage-class" = var.osdStorageClassName, + "billing-type" = var.billingType, + "cluster-encryption" = var.clusterEncryption, + "ibm-cos-endpoint"= var.ibmCosEndpoint, + "ibm-cos-location"= var.ibmCosLocation, + "ignore-noobaa"= var.ignoreNoobaa, + "kms-base-url"= var.kmsBaseUrl, + "kms-encryption"= var.kmsEncryption, + "kms-instance-id"= var.kmsInstanceId, + "kms-instance-name"= var.kmsInstanceName, + "kms-token-url"= var.kmsTokenUrl, + "odf-upgrade"= var.ocsUpgrade, + "perform-cleanup"= var.performCleanup, + "disable-noobaa-LB"= var.disableNoobaaLB, + "encryption-intransit"= var.encryptionInTransit, + "worker-pools"=var.workerPools, + "worker-nodes"= var.workerNodes, + "add-single-replica-pool" = var.addSingleReplicaPool, + "taint-nodes" = var.taintNodes, + "prepare-for-disaster-recovery" = var.prepareForDisasterRecovery, + "resource-profile" = var.resourceProfile, + "use-ceph-rbd-as-default-storage-class" = var.useCephRBDAsDefaultStorageClass, + "enable-nfs" = var.enableNFS + } + user_secret_parameters = { + "iam-api-key"= var.iamAPIKey, + "ibm-cos-access-key" = var.ibmCosAccessKey, + "kms-root-key" = var.kmsRootKey, + "kms-api-key" = var.kmsApiKey + } + delete_assignments = var.deleteAssignments + update_assignments = var.updateAssignments +} + +resource "ibm_satellite_storage_assignment" "storage_assignment" { + assignment_name = var.assignmentName + cluster = var.cluster + controller = var.location + config = var.configName + depends_on = [ibm_satellite_storage_configuration.storage_configuration] + update_config_revision = var.updateConfigRevision +} diff --git a/examples/openshift-data-foundation/satellite/odf-remote/4.16/variables.tf b/examples/openshift-data-foundation/satellite/odf-remote/4.16/variables.tf new file mode 100644 index 0000000000..26e263a282 --- /dev/null +++ b/examples/openshift-data-foundation/satellite/odf-remote/4.16/variables.tf @@ -0,0 +1,269 @@ +variable "ibmcloud_api_key" { + type = string + description = "IBM Cloud API Key" +} + +variable "iamAPIKey" { + type = string + description = "Your IBM Cloud API Key" +} + +variable "location" { + type = string + description = "The satellite location where you want to create your configuration" +} + +variable "configName" { + type = string + description = "The name of your storage configuration" +} + +variable "storageTemplateName" { + type = string + description = "The storage template for your configuration." +} + +variable "storageTemplateVersion" { + type = string + description = "The version of the storage template." +} + +variable "region" { + type = string + description = "Enter Satellite Location Region" +} + +variable "odfVersion" { + type = string + default = "4.15.0" + description = "Provide the ODF Version you wish to install on your cluster" +} + +variable "numOfOsd" { +type = string +default = "1" +description = "Number of Osd" +} + +variable "osdDevicePaths" { +type = string +description = "IDs of the disks to be used for OSD pods if using local disks or standard classic cluster" +default = null +} + +variable "ocsUpgrade" { + type = string + default = "false" + description = "Set to true to upgrade Ocscluster" + +} + +variable "clusterEncryption" { + type = string + default = "false" + description = "Enable at-rest encryption of all disks in the storage cluster." +} + + +variable "billingType" { + type = string + default = "advanced" + description = "Choose between advanced and essentials" +} + +variable "ignoreNoobaa" { + type = bool + default = false + description = "Set to true if you do not want MultiCloudGateway" +} + +variable "performCleanup" { + type = bool + default = false + description = "Set to true if you want to perform cleanup during assignment deletion" +} + +variable "ibmCosEndpoint" { + type = string + default = null + description = "The IBM COS regional public endpoint" +} + +variable "ibmCosLocation" { + type = string + default = null + description = "The location constraint that you want to use when creating your bucket. For example us-east-standard." +} + +variable "ibmCosSecretKey" { + type = string + default = null + description = "Your IBM COS HMAC secret access key." +} + +variable "ibmCosAccessKey" { + type = string + default = null + description = "Your IBM COS HMAC access key ID." +} + +variable "kmsApiKey" { + type = string + default = null + description = "IAM API key to access the KMS instance. The API key that you provide must have at least Viewer access to the KMS instance." +} + +variable "kmsRootKey" { + type = string + default = null + description = "KMS root key of your instance." +} + +variable "osdSize" { + type = string + default = "250Gi" + description = "Enter the size for the storage devices that you want to provision for the Object Storage Daemon (OSD) pods." +} + +variable "osdStorageClassName" { + type = string + default = "ibmc-vpc-block-metro-10iops-tier" + description = "Enter the storage class to be used to provision block volumes for Object Storage Daemon (OSD) pods." + +} + +variable "autoDiscoverDevices" { + type = string + default = "false" + description = "Set to true if automatically discovering local disks" +} + +variable "kmsEncryption" { + type = string + default = "false" + description = "Set to true to enable HPCS Encryption" +} + +variable "kmsInstanceName" { + type = string + default = null + description = "Please provide HPCS service name" +} + +variable "kmsSecretName" { + type = string + default = null + description = "Please provide the HPCS secret name" +} + +variable "workerPools" { + type = string + default = null + description = "Provide the names/ID of the workerpool on which to install ODF. Specify either workerpool or worker nodes to select storage nodes. If none of them specified, ODF will install on all workers." +} + +variable "workerNodes" { + type = string + default = null + description = "Provide the names of the worker nodes on which to install ODF. Leave blank to install ODF on all worker nodes." +} + +variable "kmsInstanceId" { + type = string + default = null + description = "Please provide HPCS Service ID" +} + +variable "kmsBaseUrl" { + type = string + default = null + description = "Please provide HPCS Base URL" +} + +variable "kmsTokenUrl" { + type = string + default = null + description = "Please provide HPCS token URL" +} + +variable "encryptionInTransit" { + type = bool + default = false + description = "Enter true to enable in-transit encryption. Enabling in-transit encryption does not affect the existing mapped or mounted volumes. After a volume is mapped/mounted, it retains the encryption settings that were used when it was initially mounted. To change the encryption settings for existing volumes, they must be remounted again one-by-one." +} + +variable "disableNoobaaLB" { + type = bool + default = false + description = "Specify true to disable to NooBaa public load balancer." +} + +variable "cluster" { + type = string + description = "Cluster ID or Name you wish to assign your configuration to." +} + +variable "assignmentName" { + type = string + description = "Name of your storage assignment to a cluster" +} + +variable "updateConfigRevision" { + type = bool + default = false + description = "Set to true if you want to update the assignment with the latest configuration revision" +} + +variable "deleteAssignments" { + type = bool + default = false + description = "Set to true if you want to delete all the assignments of the configuration, during storage configuration destroy" +} + +variable "updateAssignments" { + type = bool + default = false + description = "Set to true if you want to update all the configuration's assignments with the latest revision" +} + +variable "taintNodes" { + type = bool + default = false + description = "Specify true to taint the selected worker nodes so that only OpenShift Data Foundation pods can run on those nodes. Use this option only if you limit ODF to a subset of nodes in your cluster." +} + +variable "addSingleReplicaPool" { + type = bool + default = false + description = "Specify true to create a single replica pool without data replication, increasing the risk of data loss, data corruption, and potential system instability." +} + +variable "prepareForDisasterRecovery" { + type = bool + default = false + description = "Specify true to set up the storage system for disaster recovery service with the essential configurations in place. This allows seamless implementation of disaster recovery strategies for your workloads." +} + +variable "enableNFS" { + + type = bool + default = false + description = "Enabling this allows you to create exports using Network File System (NFS) that can then be accessed internally or externally from the OpenShift cluster." + +} + +variable "useCephRBDAsDefaultStorageClass" { + + type = bool + default = false + description = "Enable to set the Ceph RADOS block device (RBD) storage class as the default storage class during the deployment of OpenShift Data Foundation" + +} + +variable "resourceProfile" { + + type = string + default = "balanced" + description = "Provides an option to choose a resource profile based on the availability of resources during deployment. Choose between lean, balanced and performance." + +} diff --git a/go.mod b/go.mod index 238fb8849e..0c75214d20 100644 --- a/go.mod +++ b/go.mod @@ -5,13 +5,13 @@ go 1.22.4 toolchain go1.22.5 require ( - github.com/IBM-Cloud/bluemix-go v0.0.0-20240926024252-81b3928fd062 + github.com/IBM-Cloud/bluemix-go v0.0.0-20241117121028-a3be206688b3 github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20240725064144-454a2ae23113 - github.com/IBM-Cloud/power-go-client v1.8.3 + github.com/IBM-Cloud/power-go-client v1.9.0 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.7.0 + github.com/IBM/cloud-databases-go-sdk v0.7.1 github.com/IBM/cloudant-go-sdk v0.8.0 github.com/IBM/code-engine-go-sdk v0.0.0-20240808131715-b9d168602dac github.com/IBM/configuration-aggregator-go-sdk v0.0.2 @@ -29,7 +29,7 @@ require ( github.com/IBM/keyprotect-go-client v0.15.1 github.com/IBM/logs-go-sdk v0.3.0 github.com/IBM/logs-router-go-sdk v1.0.5 - github.com/IBM/mqcloud-go-sdk v0.1.0 + github.com/IBM/mqcloud-go-sdk v0.2.0 github.com/IBM/networking-go-sdk v0.49.0 github.com/IBM/platform-services-go-sdk v0.70.0 github.com/IBM/project-go-sdk v0.3.5 @@ -40,7 +40,7 @@ require ( github.com/IBM/secrets-manager-go-sdk/v2 v2.0.7 github.com/IBM/vmware-go-sdk v0.1.2 github.com/IBM/vpc-beta-go-sdk v0.8.0 - github.com/IBM/vpc-go-sdk v0.62.0 + github.com/IBM/vpc-go-sdk v0.63.1 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 diff --git a/go.sum b/go.sum index fa2621d224..ebd142a0a4 100644 --- a/go.sum +++ b/go.sum @@ -113,13 +113,13 @@ 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-20240926024252-81b3928fd062 h1:VCFztsAnZBuzyVeOrpFEJFPiKDyx6tVOLe+p3VBsfWk= -github.com/IBM-Cloud/bluemix-go v0.0.0-20240926024252-81b3928fd062/go.mod h1:/7hMjdZA6fEpd/dQAOEABxKEwN0t72P3PlpEDu0Y7bE= +github.com/IBM-Cloud/bluemix-go v0.0.0-20241117121028-a3be206688b3 h1:eIa+RXJZ188p1S5q+fu3feDiL6dtp0W2IB1LM0B/plE= +github.com/IBM-Cloud/bluemix-go v0.0.0-20241117121028-a3be206688b3/go.mod h1:/7hMjdZA6fEpd/dQAOEABxKEwN0t72P3PlpEDu0Y7bE= github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20240725064144-454a2ae23113 h1:f2Erqfea1dKpaTFagTJM6W/wnD3JGq/Vn9URh8nuRwk= github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20240725064144-454a2ae23113/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.8.3 h1:QsBuIS6KvKsiEpe0yiHYKhWgXlqkcJ7XqFHtATj8Yh4= -github.com/IBM-Cloud/power-go-client v1.8.3/go.mod h1:UDyXeIKEp6r7yWUXYu3r0ZnFSlNZ2YeQTHwM2Tmlgv0= +github.com/IBM-Cloud/power-go-client v1.9.0 h1:nnErpb/7TJQe8P7OfIlJPhSJVq5oyuCJlMje9Ry6XEY= +github.com/IBM-Cloud/power-go-client v1.9.0/go.mod h1:UDyXeIKEp6r7yWUXYu3r0ZnFSlNZ2YeQTHwM2Tmlgv0= github.com/IBM-Cloud/softlayer-go v1.0.5-tf h1:koUAyF9b6X78lLLruGYPSOmrfY2YcGYKOj/Ug9nbKNw= github.com/IBM-Cloud/softlayer-go v1.0.5-tf/go.mod h1:6HepcfAXROz0Rf63krk5hPZyHT6qyx2MNvYyHof7ik4= github.com/IBM/apigateway-go-sdk v0.0.0-20210714141226-a5d5d49caaca h1:crniVcf+YcmgF03NmmfonXwSQ73oJF+IohFYBwknMxs= @@ -128,8 +128,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.7.0 h1:prvLebKD1kcIk81D6yRhOr/TWp1VQJGLhGAasQr7RtA= -github.com/IBM/cloud-databases-go-sdk v0.7.0/go.mod h1:JYucI1PdwqbAd8XGdDAchxzxRP7bxOh1zUnseovHKsc= +github.com/IBM/cloud-databases-go-sdk v0.7.1 h1:5kK4/3NUsGxZzmuUe+1ftajpOQbeDVh5VeemrPgROP4= +github.com/IBM/cloud-databases-go-sdk v0.7.1/go.mod h1:JYucI1PdwqbAd8XGdDAchxzxRP7bxOh1zUnseovHKsc= github.com/IBM/cloudant-go-sdk v0.8.0 h1:XzaqZFy5fm1Q9+iK52X5zRW39SHaahT9pf5SRgVTsTY= github.com/IBM/cloudant-go-sdk v0.8.0/go.mod h1:zDGBs8ideVtn9MehXbIQNI3852B68BsMtKJvq3iPn/Q= github.com/IBM/code-engine-go-sdk v0.0.0-20240808131715-b9d168602dac h1:9Y5TB9Ar2SM6JPr2kM6c9pHSdSuHMDCIcbvTa/hNTj4= @@ -172,8 +172,8 @@ github.com/IBM/logs-go-sdk v0.3.0 h1:FHzTCCMyp9DvQGXgkppzcOPywC4ggt7x8xu0MR5h8xI github.com/IBM/logs-go-sdk v0.3.0/go.mod h1:yv/GCXC4/p+MZEeXl4xjZAOMvDAVRwu61WyHZFKFXQM= github.com/IBM/logs-router-go-sdk v1.0.5 h1:r0kC1+HfmSeQCD6zQTUp4PDI/zp4Ueo1Zo19ipHuNlw= github.com/IBM/logs-router-go-sdk v1.0.5/go.mod h1:tCN2vFgu5xG0ob9iJcxi5M4bJ6mWmu3nhmRPnvlwev0= -github.com/IBM/mqcloud-go-sdk v0.1.0 h1:fWt4uisg5GbbsfNmAxx5/6c5gQIPM+VrEsTtnimELeA= -github.com/IBM/mqcloud-go-sdk v0.1.0/go.mod h1:LesMQlKHXvdks4jqQLZH7HfATY5lvTzHuwQU5+y7b2g= +github.com/IBM/mqcloud-go-sdk v0.2.0 h1:QOWk8ZGk0QfIL0MOGTKzNdM3Qe0Hk+ifAFtNSFQo5HU= +github.com/IBM/mqcloud-go-sdk v0.2.0/go.mod h1:VZQKMtqmcdXKhmLhLiPuS/UHMs/5yo2tA/nD83cQt9E= github.com/IBM/networking-go-sdk v0.49.0 h1:lPS34u3C0JVrbxH+Ulua76Nwl6Frv8BEfq6LRkyvOv0= github.com/IBM/networking-go-sdk v0.49.0/go.mod h1:G9CKbmPE8gSLjN+ABh4hIZ1bMx076enl5Eekvj6zQnA= github.com/IBM/platform-services-go-sdk v0.70.0 h1:G/jEzG/8SEEc+ZDXqAsPGPWcWD2UGy99LBhPX5iiD2E= @@ -194,8 +194,8 @@ github.com/IBM/vmware-go-sdk v0.1.2 h1:5lKWFyInWz9e2hwGsoFTEoLa1jYkD30SReN0fQ10w github.com/IBM/vmware-go-sdk v0.1.2/go.mod h1:2UGPBJju3jiv5VKKBBm9a5L6bzF/aJdKOKAzJ7HaOjA= github.com/IBM/vpc-beta-go-sdk v0.8.0 h1:cEPpv4iw3Ba5W2d0AWg3TIbKeJ8y1nPuUuibR5Jt9eE= github.com/IBM/vpc-beta-go-sdk v0.8.0/go.mod h1:hORgIyTFRzXrZIK9IohaWmCRBBlYiDRagsufi7M6akE= -github.com/IBM/vpc-go-sdk v0.62.0 h1:Xga74D70ziD7nzm51ue3othHz1epMLVkGP/L6/Be+/0= -github.com/IBM/vpc-go-sdk v0.62.0/go.mod h1:VBR6bAznHsNCFA89Ue4JFQpqCcFp8F5neqbCFCyks4Q= +github.com/IBM/vpc-go-sdk v0.63.1 h1:HqQeq2wGI2pF4y0/m18EaPsOEEXFjyml+xwlLC9AiXE= +github.com/IBM/vpc-go-sdk v0.63.1/go.mod h1:VBR6bAznHsNCFA89Ue4JFQpqCcFp8F5neqbCFCyks4Q= 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= diff --git a/ibm/acctest/acctest.go b/ibm/acctest/acctest.go index d78f6ea5f8..dbcc0de99e 100644 --- a/ibm/acctest/acctest.go +++ b/ibm/acctest/acctest.go @@ -90,6 +90,7 @@ var ( ISResourceCrn string ISCIDR string ISCIDR2 string + ISIPV4Address string ISPublicSSHKeyFilePath string ISPrivateSSHKeyFilePath string ISAddressPrefixCIDR string @@ -132,14 +133,17 @@ var ( // MQ on Cloud var ( - MqcloudConfigEndpoint string - MqcloudInstanceID string - MqcloudQueueManagerID string - MqcloudKSCertFilePath string - MqcloudTSCertFilePath string - MqCloudQueueManagerLocation string - MqCloudQueueManagerVersion string - MqCloudQueueManagerVersionUpdate string + MqcloudConfigEndpoint string + MqcloudDeploymentID string + MqcloudCapacityID string + MqcloudQueueManagerID string + MqcloudKSCertFilePath string + MqcloudTSCertFilePath string + MqCloudQueueManagerLocation string + MqCloudQueueManagerVersion string + MqCloudQueueManagerVersionUpdate string + MqCloudVirtualPrivateEndPointTargetCrn string + MqCloudVirtualPrivateEndPointTrustedProfile string ) // Logs @@ -420,6 +424,13 @@ var ( PcsIamServiceRegistrationId string ) +// For cluster +var ( + ISClusterNetworkProfileName string + ISInstanceGPUProfileName string + ISClusterNetworkSubnetPrefixesCidr string +) + func init() { testlogger := os.Getenv("TF_LOG") if testlogger != "" { @@ -764,6 +775,11 @@ func init() { ISCIDR2 = "10.240.64.0/24" fmt.Println("[INFO] Set the environment variable SL_CIDR_2 for testing ibm_is_subnet else it is set to default value '10.240.64.0/24'") } + ISIPV4Address = os.Getenv("IS_IPV4_ADDRESS") + if ISIPV4Address == "" { + ISIPV4Address = "10.240.0.6" + fmt.Println("[INFO] Set the environment variable IS_IPV4_ADDRESS for testing ibm_is_instance else it is set to default value '10.240.0.6'") + } AccountId = os.Getenv("IS_ACCOUNT_ID") if AccountId == "" { @@ -771,6 +787,23 @@ func init() { fmt.Println("[INFO] Set the environment variable IS_ACCOUNT_ID for testing private_path_service_gateway_account_policy else it is set to default value 'fee82deba12e4c0fb69c3b09d1f12345'") } + ISClusterNetworkProfileName = os.Getenv("IS_CLUSTER_NETWORK_PROFILE_NAME") + if ISClusterNetworkProfileName == "" { + ISClusterNetworkProfileName = "h100" + fmt.Println("[INFO] Set the environment variable IS_CLUSTER_NETWORK_PROFILE_NAME for testing cluster_network_profile else it is set to default value 'h100'") + } + ISInstanceGPUProfileName = os.Getenv("IS_INSTANCE_GPU_PROFILE_NAME") + if ISInstanceGPUProfileName == "" { + ISInstanceGPUProfileName = "gx3d-160x1792x8h100" + fmt.Println("[INFO] Set the environment variable IS_INSTANCE_GPU_PROFILE_NAME for testing cluster_network_attachments else it is set to default value 'gx3d-160x1792x8h100'") + } + + ISClusterNetworkSubnetPrefixesCidr = os.Getenv("IS_CLUSTER_NETWORK_SUBNET_PREFIXES_CIDR") + if ISClusterNetworkSubnetPrefixesCidr == "" { + ISClusterNetworkSubnetPrefixesCidr = "10.1.0.0/24" + fmt.Println("[INFO] Set the environment variable IS_CLUSTER_NETWORK_SUBNET_PREFIXES_CIDR for testing cluster_network else it is set to default value '10.1.0.0/24'") + } + ISAddressPrefixCIDR = os.Getenv("SL_ADDRESS_PREFIX_CIDR") if ISAddressPrefixCIDR == "" { ISAddressPrefixCIDR = "10.120.0.0/24" @@ -1868,9 +1901,13 @@ func init() { fmt.Println("[INFO] Set the environment variable IBMCLOUD_MQCLOUD_CONFIG_ENDPOINT for ibm_mqcloud service else tests will fail if this is not set correctly") } - 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") + MqcloudDeploymentID = os.Getenv("IBM_MQCLOUD_DEPLOYMENT_ID") + if MqcloudDeploymentID == "" { + fmt.Println("[INFO] Set the environment variable IBM_MQCLOUD_DEPLOYMENT_ID for ibm_mqcloud_queue_manager resource or datasource else tests will fail if this is not set correctly") + } + MqcloudCapacityID = os.Getenv("IBM_MQCLOUD_CAPACITY_ID") + if MqcloudCapacityID == "" { + fmt.Println("[INFO] Set the environment variable IBM_MQCLOUD_DEPLOYMENT_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 == "" { @@ -1896,6 +1933,14 @@ func init() { if MqCloudQueueManagerVersionUpdate == "" { fmt.Println("[INFO] Set the environment variable IBM_MQCLOUD_QUEUEMANAGER_VERSIONUPDATE for ibm_mqcloud_queue_manager resource or datasource else tests will fail if this is not set correctly") } + MqCloudVirtualPrivateEndPointTargetCrn = os.Getenv(("IBM_MQCLOUD_TARGET_CRN")) + if MqCloudVirtualPrivateEndPointTargetCrn == "" { + fmt.Println("[INFO] Set the environment variable IBM_MQCLOUD_TARGET_CRN for ibm_mqcloud_virtual_private_endpoint resource or datasource else tests will fail if this is not set correctly") + } + MqCloudVirtualPrivateEndPointTrustedProfile = os.Getenv(("IBM_MQCLOUD_TRUSTED_PROFILE")) + if MqCloudVirtualPrivateEndPointTrustedProfile == "" { + fmt.Println("[INFO] Set the environment variable IBM_MQCLOUD_TRUSTED_PROFILE for ibm_mqcloud_virtual_private_endpoint resource or datasource else tests will fail if this is not set correctly") + } LogsInstanceId = os.Getenv("IBMCLOUD_LOGS_SERVICE_INSTANCE_ID") if LogsInstanceId == "" { fmt.Println("[INFO] Set the environment variable IBMCLOUD_LOGS_SERVICE_INSTANCE_ID for testing cloud logs related operations") @@ -2267,8 +2312,11 @@ func TestAccPreCheckMqcloud(t *testing.T) { if MqcloudConfigEndpoint == "" { t.Fatal("IBMCLOUD_MQCLOUD_CONFIG_ENDPOINT must be set for acceptance tests") } - if MqcloudInstanceID == "" { - t.Fatal("IBM_MQCLOUD_INSTANCE_ID must be set for acceptance tests") + if MqcloudDeploymentID == "" { + t.Fatal("IBM_MQCLOUD_DEPLOYMENT_ID must be set for acceptance tests") + } + if MqcloudCapacityID == "" { + t.Fatal("IBM_MQCLOUD_CAPACITY_ID must be set for acceptance tests") } if MqcloudQueueManagerID == "" { t.Fatal("IBM_MQCLOUD_QUEUEMANAGER_ID must be set for acceptance tests") diff --git a/ibm/conns/config.go b/ibm/conns/config.go index 0c0d414f02..3931be130d 100644 --- a/ibm/conns/config.go +++ b/ibm/conns/config.go @@ -1262,7 +1262,7 @@ func (session clientSession) ProjectV1() (*project.ProjectV1, error) { return session.projectClient, session.projectClientErr } -// MQ on Cloud +// MQaaS func (session clientSession) MqcloudV1() (*mqcloudv1.MqcloudV1, error) { if session.mqcloudClientErr != nil { sessionMqcloudClient := session.mqcloudClient @@ -1567,20 +1567,10 @@ func (c *Config) ClientSession() (interface{}, error) { var authenticator core.Authenticator - if c.BluemixAPIKey != "" || sess.BluemixSession.Config.IAMRefreshToken != "" { - if c.BluemixAPIKey != "" { - authenticator = &core.IamAuthenticator{ - ApiKey: c.BluemixAPIKey, - URL: EnvFallBack([]string{"IBMCLOUD_IAM_API_ENDPOINT"}, iamURL), - } - } else { - // Construct the IamAuthenticator with the IAM refresh token. - authenticator = &core.IamAuthenticator{ - RefreshToken: sess.BluemixSession.Config.IAMRefreshToken, - ClientId: "bx", - ClientSecret: "bx", - URL: EnvFallBack([]string{"IBMCLOUD_IAM_API_ENDPOINT"}, iamURL), - } + if c.BluemixAPIKey != "" { + authenticator = &core.IamAuthenticator{ + ApiKey: c.BluemixAPIKey, + URL: EnvFallBack([]string{"IBMCLOUD_IAM_API_ENDPOINT"}, "https://iam.cloud.ibm.com") + "/identity/token", } } else if strings.HasPrefix(sess.BluemixSession.Config.IAMAccessToken, "Bearer") { authenticator = &core.BearerTokenAuthenticator{ @@ -3448,7 +3438,7 @@ func (c *Config) ClientSession() (interface{}, error) { session.cdTektonPipelineClientErr = fmt.Errorf("Error occurred while configuring CD Tekton Pipeline service: %q", err) } - // MQ Cloud Service Configuration + // MQaaS 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) @@ -3463,7 +3453,7 @@ func (c *Config) ClientSession() (interface{}, error) { URL: EnvFallBack([]string{"IBMCLOUD_MQCLOUD_CONFIG_ENDPOINT"}, mqCloudURL), } - // Construct the service client for MQ Cloud. + // Construct the service client for MQaaS. session.mqcloudClient, err = mqcloudv1.NewMqcloudV1(mqcloudClientOptions) if err == nil { // Enable retries for API calls @@ -3473,7 +3463,7 @@ func (c *Config) ClientSession() (interface{}, error) { "X-Original-User-Agent": {fmt.Sprintf("terraform-provider-ibm/%s", version.Version)}, }) } else { - session.mqcloudClientErr = fmt.Errorf("Error occurred while configuring MQ on Cloud service: %q", err) + session.mqcloudClientErr = fmt.Errorf("Error occurred while configuringMQaaS service: %q", err) } // VMware as a Service diff --git a/ibm/flex/structures.go b/ibm/flex/structures.go index 41c407e251..dadae9c479 100644 --- a/ibm/flex/structures.go +++ b/ibm/flex/structures.go @@ -2903,6 +2903,15 @@ func ResourceTagsCustomizeDiff(diff *schema.ResourceDiff) error { return nil } +func OnlyInUpdateDiff(resources []string, diff *schema.ResourceDiff) error { + for _, r := range resources { + if diff.HasChange(r) && diff.Id() == "" { + return fmt.Errorf("the %s can't be used at create time", r) + } + } + return nil +} + func ResourceValidateAccessTags(diff *schema.ResourceDiff, meta interface{}) error { if value, ok := diff.GetOkExists("access_tags"); ok { diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go index c9bc22c434..71d6d365a5 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -34,6 +34,7 @@ import ( "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/contextbasedrestrictions" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/cos" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/database" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/db2" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/directlink" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/dnsservices" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/enterprise" @@ -319,6 +320,7 @@ func Provider() *schema.Provider { "ibm_database_tasks": database.DataSourceIBMDatabaseTasks(), "ibm_database_backup": database.DataSourceIBMDatabaseBackup(), "ibm_database_backups": database.DataSourceIBMDatabaseBackups(), + "ibm_db2": db2.DataSourceIBMDb2Instance(), "ibm_compute_bare_metal": classicinfrastructure.DataSourceIBMComputeBareMetal(), "ibm_compute_image_template": classicinfrastructure.DataSourceIBMComputeImageTemplate(), "ibm_compute_placement_group": classicinfrastructure.DataSourceIBMComputePlacementGroup(), @@ -371,6 +373,7 @@ func Provider() *schema.Provider { "ibm_iam_access_group_template_versions": iamaccessgroup.DataSourceIBMIAMAccessGroupTemplateVersions(), "ibm_iam_access_group_template_assignment": iamaccessgroup.DataSourceIBMIAMAccessGroupTemplateAssignment(), "ibm_iam_account_settings": iamidentity.DataSourceIBMIAMAccountSettings(), + "ibm_iam_effective_account_settings": iamidentity.DataSourceIBMIamEffectiveAccountSettings(), "ibm_iam_auth_token": iamidentity.DataSourceIBMIAMAuthToken(), "ibm_iam_role_actions": iampolicy.DataSourceIBMIAMRoleAction(), "ibm_iam_users": iamidentity.DataSourceIBMIAMUsers(), @@ -425,6 +428,20 @@ func Provider() *schema.Provider { "ibm_is_bare_metal_server": vpc.DataSourceIBMIsBareMetalServer(), "ibm_is_bare_metal_servers": vpc.DataSourceIBMIsBareMetalServers(), + // cluster + "ibm_is_cluster_network": vpc.DataSourceIBMIsClusterNetwork(), + "ibm_is_cluster_networks": vpc.DataSourceIBMIsClusterNetworks(), + "ibm_is_cluster_network_interface": vpc.DataSourceIBMIsClusterNetworkInterface(), + "ibm_is_cluster_network_interfaces": vpc.DataSourceIBMIsClusterNetworkInterfaces(), + "ibm_is_cluster_network_profile": vpc.DataSourceIBMIsClusterNetworkProfile(), + "ibm_is_cluster_network_profiles": vpc.DataSourceIBMIsClusterNetworkProfiles(), + "ibm_is_cluster_network_subnet": vpc.DataSourceIBMIsClusterNetworkSubnet(), + "ibm_is_cluster_network_subnets": vpc.DataSourceIBMIsClusterNetworkSubnets(), + "ibm_is_cluster_network_subnet_reserved_ip": vpc.DataSourceIBMIsClusterNetworkSubnetReservedIP(), + "ibm_is_cluster_network_subnet_reserved_ips": vpc.DataSourceIBMIsClusterNetworkSubnetReservedIps(), + "ibm_is_instance_cluster_network_attachment": vpc.DataSourceIBMIsInstanceClusterNetworkAttachment(), + "ibm_is_instance_cluster_network_attachments": vpc.DataSourceIBMIsInstanceClusterNetworkAttachments(), + "ibm_is_dedicated_host": vpc.DataSourceIbmIsDedicatedHost(), "ibm_is_dedicated_hosts": vpc.DataSourceIbmIsDedicatedHosts(), "ibm_is_dedicated_host_profile": vpc.DataSourceIbmIsDedicatedHostProfile(), @@ -668,6 +685,7 @@ func Provider() *schema.Provider { "ibm_pi_network_address_groups": power.DataSourceIBMPINetworkAddressGroups(), "ibm_pi_network_interface": power.DataSourceIBMPINetworkInterface(), "ibm_pi_network_interfaces": power.DataSourceIBMPINetworkInterfaces(), + "ibm_pi_network_peers": power.DataSourceIBMPINetworkPeers(), "ibm_pi_network_port": power.DataSourceIBMPINetworkPort(), "ibm_pi_network_security_group": power.DataSourceIBMPINetworkSecurityGroup(), "ibm_pi_network_security_groups": power.DataSourceIBMPINetworkSecurityGroups(), @@ -817,13 +835,15 @@ func Provider() *schema.Provider { "ibm_metrics_router_routes": metricsrouter.DataSourceIBMMetricsRouterRoutes(), // MQ on Cloud - "ibm_mqcloud_queue_manager_options": mqcloud.DataSourceIbmMqcloudQueueManagerOptions(), - "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(), + "ibm_mqcloud_queue_manager_options": mqcloud.DataSourceIbmMqcloudQueueManagerOptions(), + "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(), + "ibm_mqcloud_virtual_private_endpoint_gateways": mqcloud.DataSourceIbmMqcloudVirtualPrivateEndpointGateways(), + "ibm_mqcloud_virtual_private_endpoint_gateway": mqcloud.DataSourceIbmMqcloudVirtualPrivateEndpointGateway(), // Security and Complaince Center(soon to be deprecated) "ibm_scc_account_location": scc.DataSourceIBMSccAccountLocation(), @@ -1033,6 +1053,7 @@ func Provider() *schema.Provider { "ibm_cis": cis.ResourceIBMCISInstance(), "ibm_database": database.ResourceIBMDatabaseInstance(), + "ibm_db2": db2.ResourceIBMDb2Instance(), "ibm_cis_domain": cis.ResourceIBMCISDomain(), "ibm_cis_domain_settings": cis.ResourceIBMCISSettings(), "ibm_cis_firewall": cis.ResourceIBMCISFirewallRecord(), @@ -1170,6 +1191,13 @@ func Provider() *schema.Provider { "ibm_is_backup_policy": vpc.ResourceIBMIsBackupPolicy(), "ibm_is_backup_policy_plan": vpc.ResourceIBMIsBackupPolicyPlan(), + // cluster + "ibm_is_cluster_network_interface": vpc.ResourceIBMIsClusterNetworkInterface(), + "ibm_is_cluster_network_subnet_reserved_ip": vpc.ResourceIBMIsClusterNetworkSubnetReservedIP(), + "ibm_is_cluster_network_subnet": vpc.ResourceIBMIsClusterNetworkSubnet(), + "ibm_is_cluster_network": vpc.ResourceIBMIsClusterNetwork(), + "ibm_is_instance_cluster_network_attachment": vpc.ResourceIBMIsInstanceClusterNetworkAttachment(), + // bare_metal_server "ibm_is_bare_metal_server_action": vpc.ResourceIBMIsBareMetalServerAction(), "ibm_is_bare_metal_server_disk": vpc.ResourceIBMIsBareMetalServerDisk(), @@ -1461,11 +1489,12 @@ func Provider() *schema.Provider { "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(), + "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(), + "ibm_mqcloud_virtual_private_endpoint_gateway": mqcloud.ResourceIbmMqcloudVirtualPrivateEndpointGateway(), // Security and Compliance Center(soon to be deprecated) "ibm_scc_account_settings": scc.ResourceIBMSccAccountSettings(), @@ -1857,11 +1886,12 @@ func Validator() validate.ValidatorDict { "ibm_config_aggregator_settings": configurationaggregator.ResourceIbmConfigAggregatorSettingsValidator(), // 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_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_mqcloud_virtual_private_endpoint_gateway": mqcloud.ResourceIbmMqcloudVirtualPrivateEndpointGatewayValidator(), "ibm_is_backup_policy": vpc.ResourceIBMIsBackupPolicyValidator(), "ibm_is_backup_policy_plan": vpc.ResourceIBMIsBackupPolicyPlanValidator(), @@ -1872,6 +1902,14 @@ func Validator() validate.ValidatorDict { "ibm_is_bare_metal_server_network_interface": vpc.ResourceIBMIsBareMetalServerNetworkInterfaceValidator(), "ibm_is_bare_metal_server": vpc.ResourceIBMIsBareMetalServerValidator(), + // cluster + + "ibm_is_cluster_network_interface": vpc.ResourceIBMIsClusterNetworkInterfaceValidator(), + "ibm_is_cluster_network_subnet": vpc.ResourceIBMIsClusterNetworkSubnetValidator(), + "ibm_is_cluster_network_subnet_reserved_ip": vpc.ResourceIBMIsClusterNetworkSubnetReservedIPValidator(), + "ibm_is_cluster_network": vpc.ResourceIBMIsClusterNetworkValidator(), + "ibm_is_instance_cluster_network_attachment": vpc.ResourceIBMIsInstanceClusterNetworkAttachmentValidator(), + "ibm_is_dedicated_host_group": vpc.ResourceIbmIsDedicatedHostGroupValidator(), "ibm_is_dedicated_host": vpc.ResourceIbmIsDedicatedHostValidator(), "ibm_is_dedicated_host_disk_management": vpc.ResourceIBMISDedicatedHostDiskManagementValidator(), diff --git a/ibm/service/codeengine/resource_ibm_code_engine_app.go b/ibm/service/codeengine/resource_ibm_code_engine_app.go index 43bc564958..124a120d75 100644 --- a/ibm/service/codeengine/resource_ibm_code_engine_app.go +++ b/ibm/service/codeengine/resource_ibm_code_engine_app.go @@ -269,9 +269,11 @@ func ResourceIbmCodeEngineApp() *schema.Resource { Description: "Optional maximum number of requests that can be processed concurrently per instance.", }, "scale_concurrency_target": { - Type: schema.TypeInt, - Optional: true, - Description: "Optional threshold of concurrent requests per instance at which one or more additional instances are created. Use this value to scale up instances based on concurrent number of requests. This option defaults to the value of the `scale_concurrency` option, if not specified.", + Type: schema.TypeInt, + Optional: true, + Default: 100, + ValidateFunc: validate.InvokeValidator("ibm_code_engine_app", "scale_concurrency_target"), + Description: "Optional threshold of concurrent requests per instance at which one or more additional instances are created. Use this value to scale up instances based on concurrent number of requests. This option defaults to the value of the `scale_concurrency` option, if not specified.", }, "scale_cpu_limit": { Type: schema.TypeString, @@ -467,6 +469,14 @@ func ResourceIbmCodeEngineAppValidator() *validate.ResourceValidator { Regexp: `^(manager|reader|writer|none|default)$`, MinValueLength: 0, }, + validate.ValidateSchema{ + Identifier: "scale_concurrency_target", + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, + Optional: true, + MinValue: "1", + MaxValue: "1000", + }, validate.ValidateSchema{ Identifier: "scale_cpu_limit", ValidateFunctionIdentifier: validate.ValidateRegexpLen, diff --git a/ibm/service/database/data_source_ibm_database_connection.go b/ibm/service/database/data_source_ibm_database_connection.go index e1ef5ae65e..01e982b5cb 100644 --- a/ibm/service/database/data_source_ibm_database_connection.go +++ b/ibm/service/database/data_source_ibm_database_connection.go @@ -2226,14 +2226,3 @@ func DataSourceIBMDatabaseConnectionMySQLConnectionURIToMap(model *clouddatabase } return modelMap, nil } - -func DataSourceIBMDatabaseConnectionConnectionBundleToMap(model *clouddatabasesv5.ConnectionBundle) (map[string]interface{}, error) { - modelMap := make(map[string]interface{}) - if model.Name != nil { - modelMap["name"] = *model.Name - } - if model.BundleBase64 != nil { - modelMap["bundle_base64"] = *model.BundleBase64 - } - return modelMap, nil -} diff --git a/ibm/service/database/data_source_ibm_database_point_in_time_recovery_test.go b/ibm/service/database/data_source_ibm_database_point_in_time_recovery_test.go index 0a95020e99..78cca1f1b3 100644 --- a/ibm/service/database/data_source_ibm_database_point_in_time_recovery_test.go +++ b/ibm/service/database/data_source_ibm_database_point_in_time_recovery_test.go @@ -47,9 +47,9 @@ func testAccCheckIBMDatabaseDataSourceConfig3(name string) string { plan = "standard" location = "%[2]s" tags = ["one:two"] + service_endpoints = "private" } - - `, name, acc.Region()) + `, name, acc.Region()) } func testAccCheckIBMDatabasePitrDataSourceConfigBasic(name string) string { diff --git a/ibm/service/database/data_source_ibm_database_remotes_test.go b/ibm/service/database/data_source_ibm_database_remotes_test.go index b1cb0cd6da..1bc322cc33 100644 --- a/ibm/service/database/data_source_ibm_database_remotes_test.go +++ b/ibm/service/database/data_source_ibm_database_remotes_test.go @@ -51,6 +51,7 @@ func testAccCheckIBMDatabaseDataSourceConfig4(name string) string { plan = "standard" location = "%[2]s" tags = ["one:two"] + service_endpoints = "private" } resource "ibm_database" "db_replica" { @@ -61,6 +62,7 @@ func testAccCheckIBMDatabaseDataSourceConfig4(name string) string { plan = "standard" location = "%[2]s" tags = ["one:two"] + service_endpoints = "private" depends_on = [ ibm_database.db, diff --git a/ibm/service/database/data_source_ibm_database_test.go b/ibm/service/database/data_source_ibm_database_test.go index e7feef9a48..64ad3b1c7a 100644 --- a/ibm/service/database/data_source_ibm_database_test.go +++ b/ibm/service/database/data_source_ibm_database_test.go @@ -13,7 +13,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) -func TestAccIBMDatabaseDataSource_basic(t *testing.T) { +func TestAccIBMDatabaseDataSourceBasic(t *testing.T) { t.Parallel() databaseResourceGroup := "default" var databaseInstanceOne string @@ -36,7 +36,7 @@ func TestAccIBMDatabaseDataSource_basic(t *testing.T) { resource.TestCheckResourceAttr(dataName, "plan", "standard"), resource.TestCheckResourceAttr(dataName, "location", acc.Region()), resource.TestCheckResourceAttr(dataName, "adminuser", "admin"), - resource.TestCheckResourceAttr(dataName, "groups.0.memory.0.allocation_mb", "2048"), + resource.TestCheckResourceAttr(dataName, "groups.0.memory.0.allocation_mb", "8192"), resource.TestCheckResourceAttr(dataName, "groups.0.disk.0.allocation_mb", "10240"), resource.TestCheckResourceAttr(dataName, "allowlist.#", "0"), resource.TestCheckResourceAttr(dataName, "tags.#", "1"), @@ -65,7 +65,15 @@ func testAccCheckIBMDatabaseDataSourceConfig(databaseResourceGroup string, name location = "%[3]s" tags = ["one:two"] service_endpoints = "public" + + group { + group_id = "member" + + host_flavor { + id = "multitenant" + } + } } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } diff --git a/ibm/service/database/resource_ibm_database_edb_test.go b/ibm/service/database/resource_ibm_database_edb_test.go index bf15266c83..76d945b27f 100644 --- a/ibm/service/database/resource_ibm_database_edb_test.go +++ b/ibm/service/database/resource_ibm_database_edb_test.go @@ -37,7 +37,7 @@ func TestAccIBMEDBDatabaseInstanceBasic(t *testing.T) { resource.TestCheckResourceAttr(name, "adminuser", "admin"), resource.TestCheckResourceAttr(name, "groups.0.memory.0.allocation_mb", "49152"), resource.TestCheckResourceAttr(name, "groups.0.disk.0.allocation_mb", "61440"), - resource.TestCheckResourceAttr(name, "service_endpoints", "public"), + resource.TestCheckResourceAttr(name, "service_endpoints", "public-and-private"), resource.TestCheckResourceAttr(name, "allowlist.#", "1"), resource.TestCheckResourceAttr(name, "users.#", "1"), resource.TestCheckResourceAttr(name, "tags.#", "1"), @@ -159,6 +159,7 @@ func testAccCheckIBMDatabaseInstanceEDBMinimal(databaseResourceGroup string, nam plan = "standard" location = "%[3]s" service_endpoints = "public-and-private" + group { group_id = "member" host_flavor { diff --git a/ibm/service/database/resource_ibm_database_elasticsearch_platinum_test.go b/ibm/service/database/resource_ibm_database_elasticsearch_platinum_test.go index 3191ee5e99..de598df4df 100644 --- a/ibm/service/database/resource_ibm_database_elasticsearch_platinum_test.go +++ b/ibm/service/database/resource_ibm_database_elasticsearch_platinum_test.go @@ -248,10 +248,12 @@ func TestAccIBMDatabaseInstance_ElasticsearchPlatinum_Group(t *testing.T) { func TestAccIBMDatabaseInstanceElasticsearchPlatinumImport(t *testing.T) { t.Parallel() + databaseResourceGroup := "default" + var databaseInstanceOne string + serviceName := fmt.Sprintf("tf-Es-%d", acctest.RandIntRange(10, 100)) - //serviceName := "test_acc" resourceName := "ibm_database." + serviceName resource.Test(t, resource.TestCase{ @@ -322,7 +324,7 @@ func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumBasic(databaseResourceG delete = "15m" } } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumFullyspecified(databaseResourceGroup string, name string) string { @@ -371,7 +373,7 @@ func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumFullyspecified(database } } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumReduced(databaseResourceGroup string, name string) string { @@ -403,7 +405,7 @@ func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumReduced(databaseResourc delete = "15m" } } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumGroupMigration(databaseResourceGroup string, name string) string { @@ -439,7 +441,7 @@ func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumGroupMigration(database delete = "15m" } } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumNodeBasic(databaseResourceGroup string, name string) string { @@ -485,7 +487,7 @@ func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumNodeBasic(databaseResou delete = "15m" } } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumNodeFullyspecified(databaseResourceGroup string, name string) string { @@ -538,7 +540,7 @@ func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumNodeFullyspecified(data delete = "15m" } } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumNodeReduced(databaseResourceGroup string, name string) string { @@ -575,7 +577,7 @@ func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumNodeReduced(databaseRes delete = "15m" } } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumNodeScaleOut(databaseResourceGroup string, name string) string { @@ -612,7 +614,7 @@ func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumNodeScaleOut(databaseRe delete = "15m" } } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumGroupBasic(databaseResourceGroup string, name string) string { @@ -659,7 +661,7 @@ func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumGroupBasic(databaseReso delete = "15m" } } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumGroupFullyspecified(databaseResourceGroup string, name string) string { @@ -714,7 +716,7 @@ func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumGroupFullyspecified(dat } } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumGroupReduced(databaseResourceGroup string, name string) string { @@ -752,7 +754,7 @@ func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumGroupReduced(databaseRe delete = "15m" } } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumGroupScaleOut(databaseResourceGroup string, name string) string { @@ -789,7 +791,7 @@ func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumGroupScaleOut(databaseR delete = "15m" } } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumImport(databaseResourceGroup string, name string) string { @@ -805,7 +807,7 @@ func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumImport(databaseResource service = "databases-for-elasticsearch" plan = "platinum" location = "%[3]s" - service_endpoints = "public-and-private" + service_endpoints = "public-and-private" timeouts { create = "120m" @@ -814,5 +816,5 @@ func testAccCheckIBMDatabaseInstanceElasticsearchPlatinumImport(databaseResource } } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } diff --git a/ibm/service/database/resource_ibm_database_mongodb_enterprise_test.go b/ibm/service/database/resource_ibm_database_mongodb_enterprise_test.go index 866ab9530e..fa21b34d23 100644 --- a/ibm/service/database/resource_ibm_database_mongodb_enterprise_test.go +++ b/ibm/service/database/resource_ibm_database_mongodb_enterprise_test.go @@ -80,7 +80,7 @@ func TestAccIBMMongoDBEnterpriseDatabaseInstanceBasic(t *testing.T) { ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{ - "wait_time_minutes", "adminpassword", "group"}, + "wait_time_minutes", "adminpassword", "group", "deletion_protection"}, }, }, }) diff --git a/ibm/service/database/resource_ibm_database_mongodb_test.go b/ibm/service/database/resource_ibm_database_mongodb_test.go index 70c43725bb..58b7c59e8e 100644 --- a/ibm/service/database/resource_ibm_database_mongodb_test.go +++ b/ibm/service/database/resource_ibm_database_mongodb_test.go @@ -84,8 +84,8 @@ func TestAccIBMDatabaseInstanceMongodbImport(t *testing.T) { t.Parallel() databaseResourceGroup := "default" var databaseInstanceOne string + serviceName := fmt.Sprintf("tf-Mongo-%d", acctest.RandIntRange(10, 100)) - //serviceName := "test_acc" resourceName := "ibm_database." + serviceName resource.Test(t, resource.TestCase{ @@ -108,7 +108,7 @@ func TestAccIBMDatabaseInstanceMongodbImport(t *testing.T) { ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{ - "wait_time_minutes"}, + "wait_time_minutes", "deletion_protection"}, }, }, }) diff --git a/ibm/service/database/resource_ibm_database_postgresql_test.go b/ibm/service/database/resource_ibm_database_postgresql_test.go index 2718d3b6ba..1e1e8a8173 100644 --- a/ibm/service/database/resource_ibm_database_postgresql_test.go +++ b/ibm/service/database/resource_ibm_database_postgresql_test.go @@ -5,33 +5,12 @@ package database_test import ( "fmt" - "reflect" - "strings" "testing" - "time" - 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" - rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - - "github.com/IBM-Cloud/bluemix-go/bmxerror" - "github.com/IBM-Cloud/bluemix-go/models" -) - -const ( - databaseInstanceSuccessStatus = "active" - databaseInstanceProvisioningStatus = "provisioning" - databaseInstanceProgressStatus = "in progress" - databaseInstanceInactiveStatus = "inactive" - databaseInstanceFailStatus = "failed" - databaseInstanceRemovedStatus = "removed" - databaseInstanceReclamation = "pending_reclamation" ) func TestAccIBMDatabaseInstancePostgresBasic(t *testing.T) { @@ -83,11 +62,6 @@ func TestAccIBMDatabaseInstancePostgresBasic(t *testing.T) { resource.TestCheckResourceAttr(name, "logical_replication_slot.#", "2"), ), }, - // { - // ResourceName: name, - // ImportState: true, - // ImportStateVerify: true, - // }, }, }) } @@ -184,10 +158,12 @@ func TestAccIBMDatabaseInstancePostgresGroup(t *testing.T) { func TestAccIBMDatabaseInstancePostgresImport(t *testing.T) { t.Parallel() + databaseResourceGroup := "default" + var databaseInstanceOne string + serviceName := fmt.Sprintf("tf-Pgress-%d", acctest.RandIntRange(10, 100)) - //serviceName := "test_acc" resourceName := "ibm_database." + serviceName resource.Test(t, resource.TestCase{ @@ -218,13 +194,16 @@ func TestAccIBMDatabaseInstancePostgresImport(t *testing.T) { func TestAccIBMDatabaseInstancePostgresPITR(t *testing.T) { t.Parallel() + databaseResourceGroup := "default" + var databaseInstanceOne string var databaseInstanceTwo string + serviceName := fmt.Sprintf("tf-Pgress-%d", acctest.RandIntRange(10, 100)) - //serviceName := "test_acc" pitrServiceName := serviceName + "-pitr" - resourceName := "ibm_database." + serviceName + + sourceResource := "ibm_database." + serviceName pitrResource := "ibm_database." + pitrServiceName resource.Test(t, resource.TestCase{ @@ -235,15 +214,17 @@ func TestAccIBMDatabaseInstancePostgresPITR(t *testing.T) { { Config: testAccCheckIBMDatabaseInstancePostgresMinimal(databaseResourceGroup, serviceName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIBMDatabaseInstanceExists(resourceName, &databaseInstanceOne), - resource.TestCheckResourceAttr(resourceName, "name", serviceName), - resource.TestCheckResourceAttr(resourceName, "service", "databases-for-postgresql"), - resource.TestCheckResourceAttr(resourceName, "plan", "standard"), - resource.TestCheckResourceAttr(resourceName, "location", acc.Region()), + testAccCheckIBMDatabaseInstanceExists(sourceResource, &databaseInstanceOne), + resource.TestCheckResourceAttr(sourceResource, "name", serviceName), + resource.TestCheckResourceAttr(sourceResource, "service", "databases-for-postgresql"), + resource.TestCheckResourceAttr(sourceResource, "plan", "standard"), + resource.TestCheckResourceAttr(sourceResource, "location", acc.Region()), ), }, { - Config: testAccCheckIBMDatabaseInstancePostgresMinimal_PITR(databaseResourceGroup, serviceName), + Config: acc.ConfigCompose( + testAccCheckIBMDatabaseInstancePostgresMinimal(databaseResourceGroup, serviceName), + testAccCheckIBMDatabaseInstancePostgresMinimal_PITR(databaseResourceGroup, serviceName)), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIBMDatabaseInstanceExists(pitrResource, &databaseInstanceTwo), resource.TestCheckResourceAttr(pitrResource, "name", pitrServiceName), @@ -315,128 +296,6 @@ func TestAccIBMDatabaseInstancePostgresReadReplicaPromotion(t *testing.T) { }) } -func testAccCheckIBMDatabaseInstanceDestroy(s *terraform.State) error { - rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_database" { - continue - } - - instanceID := rs.Primary.ID - - rsInst := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - instance, response, err := rsContClient.GetResourceInstance(&rsInst) - if err == nil { - if !reflect.DeepEqual(instance, models.ServiceInstance{}) && *instance.State == "active" { - return fmt.Errorf("Database still exists: %s", rs.Primary.ID) - } - } else { - if !strings.Contains(err.Error(), "404") { - return fmt.Errorf("[ERROR] Error checking if database (%s) has been destroyed: %s %s", rs.Primary.ID, err, response) - } - } - } - return nil -} - -func testAccDatabaseInstanceManuallyDelete(tfDatabaseID *string) resource.TestCheckFunc { - return func(s *terraform.State) error { - _ = testAccDatabaseInstanceManuallyDeleteUnwrapped(s, tfDatabaseID) - return nil - } -} - -func testAccDatabaseInstanceManuallyDeleteUnwrapped(s *terraform.State, tfDatabaseID *string) error { - rsConClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - instance := *tfDatabaseID - var instanceID string - if strings.HasPrefix(instance, "crn") { - instanceID = instance - } else { - _, instanceID, _ = flex.ConvertTftoCisTwoVar(instance) - } - recursive := true - deleteReq := rc.DeleteResourceInstanceOptions{ - ID: &instanceID, - Recursive: &recursive, - } - response, err := rsConClient.DeleteResourceInstance(&deleteReq) - if err != nil { - return fmt.Errorf("[ERROR] Error deleting resource instance: %s %s", err, response) - } - - _ = &resource.StateChangeConf{ - Pending: []string{databaseInstanceProgressStatus, databaseInstanceInactiveStatus, databaseInstanceSuccessStatus}, - Target: []string{databaseInstanceRemovedStatus}, - Refresh: func() (interface{}, string, error) { - rsInst := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - instance, response, err := rsConClient.GetResourceInstance(&rsInst) - if err != nil { - if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { - return instance, databaseInstanceSuccessStatus, nil - } - return nil, "", err - } - if *instance.State == databaseInstanceFailStatus { - return instance, *instance.State, fmt.Errorf("[ERROR] The resource instance %s failed to delete: %v %s", instanceID, err, response) - } - return instance, *instance.State, nil - }, - Timeout: 90 * time.Second, - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - if err != nil { - return fmt.Errorf("[ERROR] Error waiting for resource instance (%s) to be deleted: %s", instanceID, err) - } - return nil -} - -func testAccCheckIBMDatabaseInstanceExists(n string, tfDatabaseID *string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ResourceControllerV2API() - if err != nil { - return err - } - instanceID := rs.Primary.ID - - rsInst := rc.GetResourceInstanceOptions{ - ID: &instanceID, - } - instance, response, err := rsContClient.GetResourceInstance(&rsInst) - if err != nil { - if strings.Contains(err.Error(), "Object not found") || - strings.Contains(err.Error(), "status code: 404") { - *tfDatabaseID = "" - return nil - } - return fmt.Errorf("[ERROR] Error retrieving resource instance: %s %s", err, response) - } - if strings.Contains(*instance.State, "removed") { - *tfDatabaseID = "" - return nil - } - - *tfDatabaseID = instanceID - return nil - } -} - func testAccCheckIBMDatabaseInstancePostgresBasic(databaseResourceGroup string, name string) string { return fmt.Sprintf(` data "ibm_resource_group" "test_acc" { @@ -485,7 +344,7 @@ func testAccCheckIBMDatabaseInstancePostgresBasic(databaseResourceGroup string, plugin_type = "wal2json" } } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } func testAccCheckIBMDatabaseInstancePostgresFullyspecified(databaseResourceGroup string, name string) string { @@ -556,7 +415,7 @@ func testAccCheckIBMDatabaseInstancePostgresFullyspecified(databaseResourceGroup plugin_type = "wal2json" } } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } func testAccCheckIBMDatabaseInstancePostgresGroupBasic(databaseResourceGroup string, name string) string { @@ -601,7 +460,7 @@ func testAccCheckIBMDatabaseInstancePostgresGroupBasic(databaseResourceGroup str description = "desc1" } } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } func testAccCheckIBMDatabaseInstancePostgresGroupFullyspecified(databaseResourceGroup string, name string) string { @@ -654,7 +513,7 @@ func testAccCheckIBMDatabaseInstancePostgresGroupFullyspecified(databaseResource description = "desc" } } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } func testAccCheckIBMDatabaseInstancePostgresGroupReduced(databaseResourceGroup string, name string) string { @@ -691,7 +550,7 @@ func testAccCheckIBMDatabaseInstancePostgresGroupReduced(databaseResourceGroup s } } } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } func testAccCheckIBMDatabaseInstancePostgresGroupScaleOut(databaseResourceGroup string, name string) string { @@ -728,7 +587,7 @@ func testAccCheckIBMDatabaseInstancePostgresGroupScaleOut(databaseResourceGroup service_endpoints = "public" tags = ["one:two"] } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } func testAccCheckIBMDatabaseInstancePostgresImport(databaseResourceGroup string, name string) string { @@ -746,7 +605,7 @@ func testAccCheckIBMDatabaseInstancePostgresImport(databaseResourceGroup string, location = "%[3]s" service_endpoints = "public-and-private" } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } func testAccCheckIBMDatabaseInstancePostgresMinimal(databaseResourceGroup string, name string) string { @@ -764,25 +623,11 @@ func testAccCheckIBMDatabaseInstancePostgresMinimal(databaseResourceGroup string location = "%[3]s" service_endpoints = "public-and-private" } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } func testAccCheckIBMDatabaseInstancePostgresMinimal_PITR(databaseResourceGroup string, name string) string { return fmt.Sprintf(` - data "ibm_resource_group" "test_acc" { - is_default = true - # name = "%[1]s" - } - - resource "ibm_database" "%[2]s" { - resource_group_id = data.ibm_resource_group.test_acc.id - name = "%[2]s" - service = "databases-for-postgresql" - plan = "standard" - location = "%[3]s" - service_endpoints = "public-and-private" - } - resource "ibm_database" "%[2]s-pitr" { resource_group_id = data.ibm_resource_group.test_acc.id name = "%[2]s-pitr" @@ -793,7 +638,7 @@ func testAccCheckIBMDatabaseInstancePostgresMinimal_PITR(databaseResourceGroup s point_in_time_recovery_time = "" service_endpoints = "public-and-private" } - `, databaseResourceGroup, name, acc.Region()) + `, databaseResourceGroup, name, acc.Region()) } func testAccCheckIBMDatabaseInstancePostgresMinimal_ReadReplica(databaseResourceGroup string, name string) string { diff --git a/ibm/service/database/resource_ibm_helpers_test.go b/ibm/service/database/resource_ibm_helpers_test.go new file mode 100644 index 0000000000..ba0169385f --- /dev/null +++ b/ibm/service/database/resource_ibm_helpers_test.go @@ -0,0 +1,152 @@ +package database_test + +import ( + "fmt" + "reflect" + "strings" + + "time" + + 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" + + rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/IBM-Cloud/bluemix-go/bmxerror" + "github.com/IBM-Cloud/bluemix-go/models" +) + +const ( + databaseInstanceSuccessStatus = "active" + databaseInstanceProvisioningStatus = "provisioning" + databaseInstanceProgressStatus = "in progress" + databaseInstanceInactiveStatus = "inactive" + databaseInstanceFailStatus = "failed" + databaseInstanceRemovedStatus = "removed" + databaseInstanceReclamation = "pending_reclamation" +) + +func testAccCheckIBMDatabaseInstanceDestroy(s *terraform.State) error { + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_database" { + continue + } + + instanceID := rs.Primary.ID + + rsInst := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + instance, response, err := rsContClient.GetResourceInstance(&rsInst) + if err == nil { + if !reflect.DeepEqual(instance, models.ServiceInstance{}) && *instance.State == "active" { + return fmt.Errorf("Database still exists: %s", rs.Primary.ID) + } + } else { + if !strings.Contains(err.Error(), "404") { + return fmt.Errorf("[ERROR] Error checking if database (%s) has been destroyed: %s %s", rs.Primary.ID, err, response) + } + } + } + return nil +} + +func testAccDatabaseInstanceManuallyDelete(tfDatabaseID *string) resource.TestCheckFunc { + return func(s *terraform.State) error { + _ = testAccDatabaseInstanceManuallyDeleteUnwrapped(s, tfDatabaseID) + return nil + } +} + +func testAccDatabaseInstanceManuallyDeleteUnwrapped(s *terraform.State, tfDatabaseID *string) error { + rsConClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + instance := *tfDatabaseID + var instanceID string + if strings.HasPrefix(instance, "crn") { + instanceID = instance + } else { + _, instanceID, _ = flex.ConvertTftoCisTwoVar(instance) + } + recursive := true + deleteReq := rc.DeleteResourceInstanceOptions{ + ID: &instanceID, + Recursive: &recursive, + } + response, err := rsConClient.DeleteResourceInstance(&deleteReq) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting resource instance: %s %s", err, response) + } + + _ = &resource.StateChangeConf{ + Pending: []string{databaseInstanceProgressStatus, databaseInstanceInactiveStatus, databaseInstanceSuccessStatus}, + Target: []string{databaseInstanceRemovedStatus}, + Refresh: func() (interface{}, string, error) { + rsInst := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + instance, response, err := rsConClient.GetResourceInstance(&rsInst) + if err != nil { + if apiErr, ok := err.(bmxerror.RequestFailure); ok && apiErr.StatusCode() == 404 { + return instance, databaseInstanceSuccessStatus, nil + } + return nil, "", err + } + if *instance.State == databaseInstanceFailStatus { + return instance, *instance.State, fmt.Errorf("[ERROR] The resource instance %s failed to delete: %v %s", instanceID, err, response) + } + return instance, *instance.State, nil + }, + Timeout: 90 * time.Second, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + if err != nil { + return fmt.Errorf("[ERROR] Error waiting for resource instance (%s) to be deleted: %s", instanceID, err) + } + return nil +} + +func testAccCheckIBMDatabaseInstanceExists(n string, tfDatabaseID *string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + instanceID := rs.Primary.ID + + rsInst := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + instance, response, err := rsContClient.GetResourceInstance(&rsInst) + if err != nil { + if strings.Contains(err.Error(), "Object not found") || + strings.Contains(err.Error(), "status code: 404") { + *tfDatabaseID = "" + return nil + } + return fmt.Errorf("[ERROR] Error retrieving resource instance: %s %s", err, response) + } + if strings.Contains(*instance.State, "removed") { + *tfDatabaseID = "" + return nil + } + + *tfDatabaseID = instanceID + return nil + } +} diff --git a/ibm/service/db2/README.md b/ibm/service/db2/README.md new file mode 100644 index 0000000000..abeeb54494 --- /dev/null +++ b/ibm/service/db2/README.md @@ -0,0 +1,9 @@ +# 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/ibm_db2_instance) \ No newline at end of file diff --git a/ibm/service/db2/data_source_ibm_db2_instance.go b/ibm/service/db2/data_source_ibm_db2_instance.go new file mode 100644 index 0000000000..009e55ed65 --- /dev/null +++ b/ibm/service/db2/data_source_ibm_db2_instance.go @@ -0,0 +1,218 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package db2 + +import ( + "encoding/json" + "fmt" + "log" + "net/url" + "reflect" + + rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" + rg "github.com/IBM/platform-services-go-sdk/resourcemanagerv2" + + "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/service/resourcecontroller" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMDb2Instance() *schema.Resource { + riSchema := resourcecontroller.DataSourceIBMResourceInstance().Schema + + riSchema["high_availability"] = &schema.Schema{ + Description: "If you require high availability, please choose this option", + Optional: true, + Type: schema.TypeString, + } + + riSchema["instance_type"] = &schema.Schema{ + Description: "Available machine type flavours (default selection will assume smallest configuration)", + Optional: true, + Type: schema.TypeString, + } + + riSchema["backup_location"] = &schema.Schema{ + Description: "Cross Regional backups can be stored across multiple regions in a zone. Regional backups are stored in only specific region.", + Optional: true, + Type: schema.TypeString, + } + + return &schema.Resource{ + Read: dataSourceIBMDb2InstanceRead, + Schema: riSchema, + } +} + +func getInstancesNext(next *string) (string, error) { + if reflect.ValueOf(next).IsNil() { + return "", nil + } + u, err := url.Parse(*next) + if err != nil { + return "", err + } + q := u.Query() + return q.Get("next_url"), nil +} + +func dataSourceIBMDb2InstanceRead(d *schema.ResourceData, meta interface{}) error { + var instance rc.ResourceInstance + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + rsCatClient, err := meta.(conns.ClientSession).ResourceCatalogAPI() + if err != nil { + return err + } + rsCatRepo := rsCatClient.ResourceCatalog() + if _, ok := d.GetOk("name"); ok { + name := d.Get("name").(string) + resourceInstanceListOptions := rc.ListResourceInstancesOptions{ + Name: &name, + } + + if rsGrpID, ok := d.GetOk("resource_group_id"); ok { + rg := rsGrpID.(string) + resourceInstanceListOptions.ResourceGroupID = &rg + } + + if service, ok := d.GetOk("service"); ok { + + serviceOff, err := rsCatRepo.FindByName(service.(string), true) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving service offering: %s", err) + } + resourceId := serviceOff[0].ID + resourceInstanceListOptions.ResourceID = &resourceId + } + + next_url := "" + var instances []rc.ResourceInstance + for { + if next_url != "" { + resourceInstanceListOptions.Start = &next_url + } + listInstanceResponse, resp, err := rsConClient.ListResourceInstances(&resourceInstanceListOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving resource instance: %s with resp code: %s", err, resp) + } + next_url, err = getInstancesNext(listInstanceResponse.NextURL) + if err != nil { + return fmt.Errorf("[DEBUG] ListResourceInstances failed. Error occurred while parsing NextURL: %s", err) + + } + instances = append(instances, listInstanceResponse.Resources...) + if next_url == "" { + break + } + } + + var filteredInstances []rc.ResourceInstance + var location string + + if loc, ok := d.GetOk("location"); ok { + location = loc.(string) + for _, instance := range instances { + if flex.GetLocationV2(instance) == location { + filteredInstances = append(filteredInstances, instance) + } + } + } else { + filteredInstances = instances + } + + if len(filteredInstances) == 0 { + return fmt.Errorf("[ERROR] No resource instance found with name [%s]\nIf not specified please specify more filters like resource_group_id if instance doesn't exists in default group, location or service", name) + } + if len(filteredInstances) > 1 { + return fmt.Errorf("[ERROR] More than one resource instance found with name matching [%s]\nIf not specified please specify more filters like resource_group_id if instance doesn't exists in default group, location or service", name) + } + instance = filteredInstances[0] + } else if _, ok := d.GetOk("identifier"); ok { + instanceGUID := d.Get("identifier").(string) + getResourceInstanceOptions := &rc.GetResourceInstanceOptions{ + ID: &instanceGUID, + } + instances, res, err := rsConClient.GetResourceInstance(getResourceInstanceOptions) + if err != nil { + return fmt.Errorf("[ERROR] No resource instance found with id [%s\n%v]", instanceGUID, res) + } + instance = *instances + d.Set("name", instance.Name) + } + d.SetId(*instance.ID) + d.Set("status", instance.State) + d.Set("resource_group_id", instance.ResourceGroupID) + d.Set("location", instance.RegionID) + serviceOff, err := rsCatRepo.GetServiceName(*instance.ResourceID) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving service offering: %s", err) + } + + d.Set("service", serviceOff) + + d.Set(flex.ResourceName, instance.Name) + d.Set(flex.ResourceCRN, instance.CRN) + d.Set(flex.ResourceStatus, instance.State) + // ### Modifiction : Setting the onetime credientials + d.Set("onetime_credentials", instance.OnetimeCredentials) + if instance.Parameters != nil { + params, err := json.Marshal(instance.Parameters) + if err != nil { + return fmt.Errorf("[ERROR] Error marshalling instance parameters: %s", err) + } + if err = d.Set("parameters_json", string(params)); err != nil { + return fmt.Errorf("[ERROR] Error setting instance parameters json: %s", err) + } + } + rMgtClient, err := meta.(conns.ClientSession).ResourceManagerV2API() + if err != nil { + return err + } + GetResourceGroup := rg.GetResourceGroupOptions{ + ID: instance.ResourceGroupID, + } + resourceGroup, resp, err := rMgtClient.GetResourceGroup(&GetResourceGroup) + if err != nil || resourceGroup == nil { + log.Printf("[ERROR] Error retrieving resource group: %s %s", err, resp) + } + if resourceGroup != nil && resourceGroup.Name != nil { + d.Set(flex.ResourceGroupName, resourceGroup.Name) + } + d.Set("guid", instance.GUID) + if len(instance.Extensions) == 0 { + d.Set("extensions", instance.Extensions) + } else { + d.Set("extensions", flex.Flatten(instance.Extensions)) + } + + rcontroller, err := flex.GetBaseController(meta) + if err != nil { + return err + } + d.Set(flex.ResourceControllerURL, rcontroller+"/services/") + + servicePlan, err := rsCatRepo.GetServicePlanName(*instance.ResourcePlanID) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving plan: %s", err) + } + d.Set("plan", servicePlan) + d.Set("crn", instance.CRN) + tags, err := flex.GetTagsUsingCRN(meta, *instance.CRN) + if err != nil { + log.Printf( + "Error on get of resource instance tags (%s) tags: %s", d.Id(), err) + } + d.Set("tags", tags) + + d.Set("high_availability", instance.Parameters["high_availability"]) + d.Set("instance_type", instance.Parameters["instance_type"]) + d.Set("backup_location", instance.Parameters["backup_location"]) + + return nil + +} diff --git a/ibm/service/db2/resource_ibm_db2_instance.go b/ibm/service/db2/resource_ibm_db2_instance.go new file mode 100644 index 0000000000..feaae9b8ec --- /dev/null +++ b/ibm/service/db2/resource_ibm_db2_instance.go @@ -0,0 +1,261 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package db2 + +import ( + "context" + "encoding/json" + "fmt" + "log" + "os" + "strconv" + "strings" + "time" + + "github.com/IBM-Cloud/bluemix-go/models" + "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/service/resourcecontroller" + rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + RsInstanceSuccessStatus = "active" + RsInstanceProgressStatus = "in progress" + RsInstanceProvisioningStatus = "provisioning" + RsInstanceInactiveStatus = "inactive" + RsInstanceFailStatus = "failed" + RsInstanceRemovedStatus = "removed" + RsInstanceReclamation = "pending_reclamation" + RsInstanceUpdateSuccessStatus = "succeeded" +) + +func ResourceIBMDb2Instance() *schema.Resource { + riSchema := resourcecontroller.ResourceIBMResourceInstance().Schema + + riSchema["high_availability"] = &schema.Schema{ + Description: "If you require high availability, please choose this option", + Optional: true, + Type: schema.TypeString, + } + + riSchema["instance_type"] = &schema.Schema{ + Description: "Available machine type flavours (default selection will assume smallest configuration)", + Optional: true, + Type: schema.TypeString, + } + + riSchema["backup_location"] = &schema.Schema{ + Description: "Cross Regional backups can be stored across multiple regions in a zone. Regional backups are stored in only specific region.", + Optional: true, + Type: schema.TypeString, + } + + return &schema.Resource{ + Create: resourceIBMDb2InstanceCreate, + Read: resourcecontroller.ResourceIBMResourceInstanceRead, + Update: resourcecontroller.ResourceIBMResourceInstanceUpdate, + Delete: resourcecontroller.ResourceIBMResourceInstanceDelete, + Exists: resourcecontroller.ResourceIBMResourceInstanceExists, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + CustomizeDiff: customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceTagsCustomizeDiff(diff) + }, + ), + + Schema: riSchema, + } +} + +func resourceIBMDb2InstanceCreate(d *schema.ResourceData, meta interface{}) error { + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + + serviceName := d.Get("service").(string) + plan := d.Get("plan").(string) + name := d.Get("name").(string) + location := d.Get("location").(string) + + rsInst := rc.CreateResourceInstanceOptions{ + Name: &name, + } + + rsCatClient, err := meta.(conns.ClientSession).ResourceCatalogAPI() + if err != nil { + return err + } + rsCatRepo := rsCatClient.ResourceCatalog() + + serviceOff, err := rsCatRepo.FindByName(serviceName, true) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving service offering: %s", err) + } + + if metadata, ok := serviceOff[0].Metadata.(*models.ServiceResourceMetadata); ok { + if !metadata.Service.RCProvisionable { + return fmt.Errorf("%s cannot be provisioned by resource controller", serviceName) + } + } else { + return fmt.Errorf("[ERROR] Cannot create instance of resource %s\nUse 'ibm_service_instance' if the resource is a Cloud Foundry service", serviceName) + } + + servicePlan, err := rsCatRepo.GetServicePlanID(serviceOff[0], plan) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving plan: %s", err) + } + rsInst.ResourcePlanID = &servicePlan + + deployments, err := rsCatRepo.ListDeployments(servicePlan) + if err != nil { + return fmt.Errorf("[ERROR] Error retrieving deployment for plan %s : %s", plan, err) + } + if len(deployments) == 0 { + return fmt.Errorf("[ERROR] No deployment found for service plan : %s", plan) + } + deployments, supportedLocations := resourcecontroller.FilterDeployments(deployments, location) + + if len(deployments) == 0 { + locationList := make([]string, 0, len(supportedLocations)) + for l := range supportedLocations { + locationList = append(locationList, l) + } + return fmt.Errorf("[ERROR] No deployment found for service plan %s at location %s.\nValid location(s) are: %q.\nUse 'ibm_service_instance' if the service is a Cloud Foundry service", plan, location, locationList) + } + + rsInst.Target = &deployments[0].CatalogCRN + + if rsGrpID, ok := d.GetOk("resource_group_id"); ok { + rg := rsGrpID.(string) + rsInst.ResourceGroup = &rg + } else { + defaultRg, err := flex.DefaultResourceGroup(meta) + if err != nil { + return err + } + rsInst.ResourceGroup = &defaultRg + } + + params := map[string]interface{}{} + + if serviceEndpoints, ok := d.GetOk("service_endpoints"); ok { + params["service-endpoints"] = serviceEndpoints.(string) + } + if highAvailability, ok := d.GetOk("high_availability"); ok { + params["high_availability"] = highAvailability.(string) + } + if instanceType, ok := d.GetOk("instance_type"); ok { + params["instance_type"] = instanceType.(string) + } + if backupLocation, ok := d.GetOk("backup_location"); ok { + params["backup-locations"] = backupLocation.(string) + } + + if parameters, ok := d.GetOk("parameters"); ok { + temp := parameters.(map[string]interface{}) + for k, v := range temp { + if v == "true" || v == "false" { + b, _ := strconv.ParseBool(v.(string)) + params[k] = b + } else if strings.HasPrefix(v.(string), "[") && strings.HasSuffix(v.(string), "]") { + //transform v.(string) to be []string + arrayString := v.(string) + result := []string{} + trimLeft := strings.TrimLeft(arrayString, "[") + trimRight := strings.TrimRight(trimLeft, "]") + if len(trimRight) == 0 { + params[k] = result + } else { + array := strings.Split(trimRight, ",") + for _, a := range array { + result = append(result, strings.Trim(a, "\"")) + } + params[k] = result + } + } else { + params[k] = v + } + } + + } + if s, ok := d.GetOk("parameters_json"); ok { + json.Unmarshal([]byte(s.(string)), ¶ms) + } + + rsInst.Parameters = params + + //Start to create resource instance + instance, resp, err := rsConClient.CreateResourceInstance(&rsInst) + if err != nil { + log.Printf( + "Error when creating resource instance: %s, Instance info NAME->%s, LOCATION->%s, GROUP_ID->%s, PLAN_ID->%s", + err, *rsInst.Name, *rsInst.Target, *rsInst.ResourceGroup, *rsInst.ResourcePlanID) + return fmt.Errorf("[ERROR] Error when creating resource instance: %s with resp code: %s", err, resp) + } + + d.SetId(*instance.ID) + + _, err = waitForResourceInstanceCreate(d, meta) + if err != nil { + return fmt.Errorf("[ERROR] Error waiting for create resource instance (%s) to be succeeded: %s", d.Id(), err) + } + + v := os.Getenv("IC_ENV_TAGS") + if _, ok := d.GetOk("tags"); ok || v != "" { + oldList, newList := d.GetChange("tags") + err = flex.UpdateTagsUsingCRN(oldList, newList, meta, *instance.CRN) + if err != nil { + log.Printf( + "Error on create of resource instance (%s) tags: %s", d.Id(), err) + } + } + + return resourcecontroller.ResourceIBMResourceInstanceRead(d, meta) +} + +func waitForResourceInstanceCreate(d *schema.ResourceData, meta interface{}) (interface{}, error) { + rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return false, err + } + instanceID := d.Id() + resourceInstanceGet := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + + stateConf := &retry.StateChangeConf{ + Pending: []string{RsInstanceProgressStatus, RsInstanceInactiveStatus, RsInstanceProvisioningStatus}, + Target: []string{RsInstanceSuccessStatus}, + Refresh: func() (interface{}, string, error) { + instance, resp, err := rsConClient.GetResourceInstance(&resourceInstanceGet) + if err != nil { + if resp != nil && resp.StatusCode == 404 { + return nil, "", fmt.Errorf("[ERROR] The resource instance %s does not exist anymore: %v", d.Id(), err) + } + return nil, "", fmt.Errorf("[ERROR] Get the resource instance %s failed with resp code: %s, err: %v", d.Id(), resp, err) + } + if *instance.State == RsInstanceFailStatus { + return instance, *instance.State, fmt.Errorf("[ERROR] The resource instance '%s' creation failed: %v", d.Id(), err) + } + return instance, *instance.State, nil + }, + Timeout: d.Timeout(schema.TimeoutCreate), + Delay: 30 * time.Second, + MinTimeout: 30 * time.Second, + } + + return stateConf.WaitForStateContext(context.Background()) +} diff --git a/ibm/service/db2/resource_ibm_db2_instance_test.go b/ibm/service/db2/resource_ibm_db2_instance_test.go new file mode 100644 index 0000000000..306c024d57 --- /dev/null +++ b/ibm/service/db2/resource_ibm_db2_instance_test.go @@ -0,0 +1,155 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package db2_test + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2" + "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" +) + +func TestAccIBMDb2InstanceBasic(t *testing.T) { + databaseResourceGroup := "Default" + var databaseInstanceOne string + rnd := fmt.Sprintf("tf-db2-%d", acctest.RandIntRange(10, 100)) + testName := rnd + name := "ibm_db2." + testName + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMDb2InstanceDestroy, + Steps: []resource.TestStep{ + { + + Config: testAccCheckIBMDb2InstanceBasic(databaseResourceGroup, testName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMDb2InstanceExists(name, &databaseInstanceOne), + resource.TestCheckResourceAttr(name, "name", testName), + resource.TestCheckResourceAttr(name, "service", "dashdb-for-transactions"), + resource.TestCheckResourceAttr(name, "plan", "performance"), + resource.TestCheckResourceAttr(name, "location", "us-east"), + resource.TestCheckResourceAttr(name, "service_endpoints", "public-and-private"), + resource.TestCheckResourceAttr(name, "instance_type", ""), + resource.TestCheckResourceAttr(name, "tags.#", "1"), + ), + }, + }, + }) +} + +func testAccCheckIBMDb2InstanceDestroy(s *terraform.State) error { + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_db2" { + continue + } + + instanceID := rs.Primary.ID + resourceInstanceGet := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + + // Try to find the key + instance, resp, err := rsContClient.GetResourceInstance(&resourceInstanceGet) + + if err == nil { + if *instance.State == "active" { + return fmt.Errorf("Resource Instance still exists: %s", rs.Primary.ID) + } + } else { + if !strings.Contains(err.Error(), "404") { + return fmt.Errorf("[ERROR] Error checking if Resource Instance (%s) has been destroyed: %s with resp code: %s", rs.Primary.ID, err, resp) + } + } + } + + return nil +} + +func testAccCheckIBMDb2InstanceExists(n string, tfDb2ID *string) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).ResourceControllerV2API() + if err != nil { + return err + } + instanceID := rs.Primary.ID + resourceInstanceGet := rc.GetResourceInstanceOptions{ + ID: &instanceID, + } + + instance, response, err := rsContClient.GetResourceInstance(&resourceInstanceGet) + + if err != nil { + if strings.Contains(err.Error(), "Object not found") || + strings.Contains(err.Error(), "status code: 404") { + *tfDb2ID = "" + return nil + } + return fmt.Errorf("[ERROR] Error retrieving resource instance: %s %s", err, response) + } + if strings.Contains(*instance.State, "removed") { + *tfDb2ID = "" + return nil + } + + *tfDb2ID = instanceID + + return nil + } +} + +func testAccCheckIBMDb2InstanceBasic(databaseResourceGroup string, testName string) string { + return fmt.Sprintf(` + + data "ibm_resource_group" "group" { + name = "%[1]s" + } + + resource "ibm_db2" "%[2]s" { + name = "%[2]s" + service = "dashdb-for-transactions" + plan = "performance" + location = "us-east" + resource_group_id = data.ibm_resource_group.group.id + service_endpoints = "public-and-private" + instance_type = "" + high_availability = "no" + backup_location = "us" + tags = ["one:two"] + + parameters_json = < This area is primarily for IBM provider contributors and maintainers. For information on _using_ Terraform and the IBM provider, see the links below. @@ -6,6 +6,6 @@ This area is primarily for IBM provider contributors and maintainers. For inform ## 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 MQ on Cloud resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/mqcloud_queue_manager) -* IBM API Docs: [IBM API Docs for MQ on Cloud](https://cloud.ibm.com/apidocs/mq-on-cloud) -* IBM MQ on Cloud SDK: [IBM SDK for MQ on Cloud](https://github.com/IBM/mqcloud-go-sdk/tree/main/mqcloudv1) \ No newline at end of file +* IBM Provider Docs: [One of the MQaaS resources](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/mqcloud_queue_manager) +* IBM API Docs: [IBM API Docs for MQaaS](https://cloud.ibm.com/apidocs/mq-on-cloud) +* IBM MQaaS SDK: [IBM SDK for MQaaS](https://github.com/IBM/mqcloud-go-sdk/tree/main/mqcloudv1) diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_application.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_application.go index 7832401901..6a9f087107 100644 --- a/ibm/service/mqcloud/data_source_ibm_mqcloud_application.go +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_application.go @@ -2,7 +2,7 @@ // Licensed under the Mozilla Public License v2.0 /* - * IBM OpenAPI Terraform Generator Version: 3.90.0-5aad763d-20240506-203857 + * IBM OpenAPI Terraform Generator Version: 3.95.2-120e65bc-20240924-152329 */ package mqcloud @@ -29,7 +29,7 @@ func DataSourceIbmMqcloudApplication() *schema.Resource { "service_instance_guid": { Type: schema.TypeString, Required: true, - Description: "The GUID that uniquely identifies the MQ on Cloud service instance.", + Description: "The GUID that uniquely identifies the MQaaS service instance.", }, "name": { Type: schema.TypeString, @@ -134,7 +134,7 @@ func dataSourceIbmMqcloudApplicationRead(context context.Context, d *schema.Reso mapSlice := []map[string]interface{}{} for _, modelItem := range allItems { modelItem := modelItem - modelMap, err := DataSourceIbmMqcloudApplicationApplicationDetailsToMap(&modelItem) + modelMap, err := DataSourceIbmMqcloudApplicationApplicationDetailsToMap(&modelItem) // #nosec G601 if err != nil { tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_mqcloud_application", "read") return tfErr.GetDiag() diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_application_test.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_application_test.go index a5162926cd..7d31288284 100644 --- a/ibm/service/mqcloud/data_source_ibm_mqcloud_application_test.go +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_application_test.go @@ -2,7 +2,7 @@ // Licensed under the Mozilla Public License v2.0 /* - * IBM OpenAPI Terraform Generator Version: 3.90.0-5aad763d-20240506-203857 + * IBM OpenAPI Terraform Generator Version: 3.95.2-120e65bc-20240924-152329 */ package mqcloud_test @@ -22,7 +22,7 @@ import ( func TestAccIbmMqcloudApplicationDataSourceBasic(t *testing.T) { t.Parallel() - applicationDetailsServiceInstanceGuid := acc.MqcloudInstanceID + applicationDetailsServiceInstanceGuid := acc.MqcloudDeploymentID applicationDetailsName := "appdsbasic" resource.Test(t, resource.TestCase{ @@ -57,6 +57,7 @@ func testAccCheckIbmMqcloudApplicationDataSourceConfigBasic(applicationDetailsSe } func TestDataSourceIbmMqcloudApplicationApplicationDetailsToMap(t *testing.T) { + t.Parallel() checkResult := func(result map[string]interface{}) { model := make(map[string]interface{}) model["id"] = "testString" diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_keystore_certificate.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_keystore_certificate.go index fa5c85a152..3e6e310518 100644 --- a/ibm/service/mqcloud/data_source_ibm_mqcloud_keystore_certificate.go +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_keystore_certificate.go @@ -2,7 +2,7 @@ // Licensed under the Mozilla Public License v2.0 /* - * IBM OpenAPI Terraform Generator Version: 3.90.0-5aad763d-20240506-203857 + * IBM OpenAPI Terraform Generator Version: 3.95.2-120e65bc-20240924-152329 */ package mqcloud @@ -29,7 +29,7 @@ func DataSourceIbmMqcloudKeystoreCertificate() *schema.Resource { "service_instance_guid": { Type: schema.TypeString, Required: true, - Description: "The GUID that uniquely identifies the MQ on Cloud service instance.", + Description: "The GUID that uniquely identifies the MQaaS service instance.", }, "queue_manager_id": { Type: schema.TypeString, @@ -285,7 +285,7 @@ func DataSourceIbmMqcloudKeystoreCertificateChannelsDetailsToMap(model *mqcloudv channels := []map[string]interface{}{} for _, channelsItem := range model.Channels { channelsItem := channelsItem - channelsItemMap, err := DataSourceIbmMqcloudKeystoreCertificateChannelDetailsToMap(&channelsItem) + channelsItemMap, err := DataSourceIbmMqcloudKeystoreCertificateChannelDetailsToMap(&channelsItem) // #nosec G601 if err != nil { return modelMap, err } 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 index f96cb6fc46..b801f2768b 100644 --- a/ibm/service/mqcloud/data_source_ibm_mqcloud_keystore_certificate_test.go +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_keystore_certificate_test.go @@ -2,7 +2,7 @@ // Licensed under the Mozilla Public License v2.0 /* - * IBM OpenAPI Terraform Generator Version: 3.90.0-5aad763d-20240506-203857 + * IBM OpenAPI Terraform Generator Version: 3.95.2-120e65bc-20240924-152329 */ package mqcloud_test @@ -23,14 +23,15 @@ import ( ) func TestAccIbmMqcloudKeystoreCertificateDataSourceBasic(t *testing.T) { - t.Parallel() - keyStoreCertificateDetailsServiceInstanceGuid := acc.MqcloudInstanceID + keyStoreCertificateDetailsServiceInstanceGuid := acc.MqcloudDeploymentID 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) }, + PreCheck: func() { + acc.TestAccPreCheckMqcloud(t) + }, Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager.go index 857cdf7f9a..bcf8847f8b 100644 --- a/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager.go +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager.go @@ -2,7 +2,7 @@ // Licensed under the Mozilla Public License v2.0 /* - * IBM OpenAPI Terraform Generator Version: 3.90.0-5aad763d-20240506-203857 + * IBM OpenAPI Terraform Generator Version: 3.95.2-120e65bc-20240924-152329 */ package mqcloud @@ -29,7 +29,7 @@ func DataSourceIbmMqcloudQueueManager() *schema.Resource { "service_instance_guid": { Type: schema.TypeString, Required: true, - Description: "The GUID that uniquely identifies the MQ on Cloud service instance.", + Description: "The GUID that uniquely identifies the MQaaS service instance.", }, "name": { Type: schema.TypeString, @@ -189,7 +189,7 @@ func dataSourceIbmMqcloudQueueManagerRead(context context.Context, d *schema.Res mapSlice := []map[string]interface{}{} for _, modelItem := range allItems { modelItem := modelItem - modelMap, err := DataSourceIbmMqcloudQueueManagerQueueManagerDetailsToMap(&modelItem) + modelMap, err := DataSourceIbmMqcloudQueueManagerQueueManagerDetailsToMap(&modelItem) // #nosec G601 if err != nil { tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_mqcloud_queue_manager", "read") return tfErr.GetDiag() diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_options.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_options.go index 286bb883ce..2dc5e3fadd 100644 --- a/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_options.go +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_options.go @@ -2,7 +2,7 @@ // Licensed under the Mozilla Public License v2.0 /* - * IBM OpenAPI Terraform Generator Version: 3.90.0-5aad763d-20240506-203857 + * IBM OpenAPI Terraform Generator Version: 3.95.2-120e65bc-20240924-152329 */ package mqcloud @@ -29,7 +29,7 @@ func DataSourceIbmMqcloudQueueManagerOptions() *schema.Resource { "service_instance_guid": { Type: schema.TypeString, Required: true, - Description: "The GUID that uniquely identifies the MQ on Cloud service instance.", + Description: "The GUID that uniquely identifies the MQaaS service instance.", }, "locations": { Type: schema.TypeList, @@ -108,6 +108,7 @@ func dataSourceIbmMqcloudQueueManagerOptionsRead(context context.Context, d *sch if err = d.Set("sizes", configurationOptions.Sizes); err != nil { return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting sizes: %s", err), "(Data) ibm_mqcloud_queue_manager_options", "read", "set-sizes").GetDiag() } + return nil } diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_options_test.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_options_test.go index 8dcbe81cb1..e7b5deaa73 100644 --- a/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_options_test.go +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_options_test.go @@ -2,7 +2,7 @@ // Licensed under the Mozilla Public License v2.0 /* - * IBM OpenAPI Terraform Generator Version: 3.90.0-5aad763d-20240506-203857 + * IBM OpenAPI Terraform Generator Version: 3.95.2-120e65bc-20240924-152329 */ package mqcloud_test @@ -18,7 +18,7 @@ import ( func TestAccIbmMqcloudQueueManagerOptionsDataSourceBasic(t *testing.T) { t.Parallel() - service_instance_guid := acc.MqcloudInstanceID + service_instance_guid := acc.MqcloudDeploymentID resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, 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 index 9b688a37a1..bf3c198f44 100644 --- a/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_status.go +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_status.go @@ -2,7 +2,7 @@ // Licensed under the Mozilla Public License v2.0 /* - * IBM OpenAPI Terraform Generator Version: 3.90.0-5aad763d-20240506-203857 + * IBM OpenAPI Terraform Generator Version: 3.95.2-120e65bc-20240924-152329 */ package mqcloud @@ -29,7 +29,7 @@ func DataSourceIbmMqcloudQueueManagerStatus() *schema.Resource { "service_instance_guid": { Type: schema.TypeString, Required: true, - Description: "The GUID that uniquely identifies the MQ on Cloud service instance.", + Description: "The GUID that uniquely identifies the MQaaS service instance.", }, "queue_manager_id": { Type: schema.TypeString, 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 index 314ef7add9..451d67bc51 100644 --- 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 @@ -2,7 +2,7 @@ // Licensed under the Mozilla Public License v2.0 /* - * IBM OpenAPI Terraform Generator Version: 3.90.0-5aad763d-20240506-203857 +* IBM OpenAPI Terraform Generator Version: 3.95.2-120e65bc-20240924-152329 */ package mqcloud_test @@ -18,7 +18,7 @@ import ( func TestAccIbmMqcloudQueueManagerStatusDataSourceBasic(t *testing.T) { t.Parallel() - service_instance_guid := acc.MqcloudInstanceID + service_instance_guid := acc.MqcloudDeploymentID queue_manager_id := acc.MqcloudQueueManagerID resource.Test(t, resource.TestCase{ 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 index c08ba1ccc9..f1709e2845 100644 --- a/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_test.go +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_queue_manager_test.go @@ -2,7 +2,7 @@ // Licensed under the Mozilla Public License v2.0 /* - * IBM OpenAPI Terraform Generator Version: 3.90.0-5aad763d-20240506-203857 + * IBM OpenAPI Terraform Generator Version: 3.95.2-120e65bc-20240924-152329 */ package mqcloud_test @@ -24,7 +24,7 @@ import ( func TestAccIbmMqcloudQueueManagerDataSourceBasic(t *testing.T) { t.Parallel() - queueManagerDetailsServiceInstanceGuid := acc.MqcloudInstanceID + queueManagerDetailsServiceInstanceGuid := acc.MqcloudDeploymentID queueManagerDetailsName := fmt.Sprintf("tf_queue_manager_ds_basic%d", acctest.RandIntRange(10, 100)) queueManagerDetailsLocation := acc.MqCloudQueueManagerLocation queueManagerDetailsSize := "xsmall" @@ -50,7 +50,7 @@ func TestAccIbmMqcloudQueueManagerDataSourceBasic(t *testing.T) { func TestAccIbmMqcloudQueueManagerDataSourceAllArgs(t *testing.T) { t.Parallel() - queueManagerDetailsServiceInstanceGuid := acc.MqcloudInstanceID + queueManagerDetailsServiceInstanceGuid := acc.MqcloudDeploymentID queueManagerDetailsName := fmt.Sprintf("tf_queue_manager_ds_allargs%d", acctest.RandIntRange(10, 100)) queueManagerDetailsDisplayName := queueManagerDetailsName queueManagerDetailsLocation := acc.MqCloudQueueManagerLocation @@ -124,6 +124,7 @@ func testAccCheckIbmMqcloudQueueManagerDataSourceConfig(queueManagerDetailsServi } func TestDataSourceIbmMqcloudQueueManagerQueueManagerDetailsToMap(t *testing.T) { + t.Parallel() checkResult := func(result map[string]interface{}) { model := make(map[string]interface{}) model["id"] = "testString" diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_truststore_certificate.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_truststore_certificate.go index de647216eb..41cbfea40f 100644 --- a/ibm/service/mqcloud/data_source_ibm_mqcloud_truststore_certificate.go +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_truststore_certificate.go @@ -2,7 +2,7 @@ // Licensed under the Mozilla Public License v2.0 /* - * IBM OpenAPI Terraform Generator Version: 3.90.0-5aad763d-20240506-203857 + * IBM OpenAPI Terraform Generator Version: 3.95.2-120e65bc-20240924-152329 */ package mqcloud @@ -29,7 +29,7 @@ func DataSourceIbmMqcloudTruststoreCertificate() *schema.Resource { "service_instance_guid": { Type: schema.TypeString, Required: true, - Description: "The GUID that uniquely identifies the MQ on Cloud service instance.", + Description: "The GUID that uniquely identifies the MQaaS service instance.", }, "queue_manager_id": { Type: schema.TypeString, @@ -177,7 +177,6 @@ func dataSourceIbmMqcloudTruststoreCertificateRead(context context.Context, d *s if err = d.Set("total_count", flex.IntValue(trustStoreCertificateDetailsCollection.TotalCount)); err != nil { return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting total_count: %s", err), "(Data) ibm_mqcloud_truststore_certificate", "read", "set-total_count").GetDiag() } - trustStore := []map[string]interface{}{} if trustStoreCertificateDetailsCollection.TrustStore != nil { for _, modelItem := range trustStoreCertificateDetailsCollection.TrustStore { 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 index 72229f71d2..bbe0edb693 100644 --- a/ibm/service/mqcloud/data_source_ibm_mqcloud_truststore_certificate_test.go +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_truststore_certificate_test.go @@ -2,7 +2,7 @@ // Licensed under the Mozilla Public License v2.0 /* - * IBM OpenAPI Terraform Generator Version: 3.90.0-5aad763d-20240506-203857 + * IBM OpenAPI Terraform Generator Version: 3.95.2-120e65bc-20240924-152329 */ package mqcloud_test @@ -23,14 +23,15 @@ import ( ) func TestAccIbmMqcloudTruststoreCertificateDataSourceBasic(t *testing.T) { - t.Parallel() - trustStoreCertificateDetailsServiceInstanceGuid := acc.MqcloudInstanceID + trustStoreCertificateDetailsServiceInstanceGuid := acc.MqcloudDeploymentID 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) }, + PreCheck: func() { + acc.TestAccPreCheckMqcloud(t) + }, Providers: acc.TestAccProviders, Steps: []resource.TestStep{ { diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_user.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_user.go index b46e6465ec..315f8694d7 100644 --- a/ibm/service/mqcloud/data_source_ibm_mqcloud_user.go +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_user.go @@ -2,7 +2,7 @@ // Licensed under the Mozilla Public License v2.0 /* - * IBM OpenAPI Terraform Generator Version: 3.90.0-5aad763d-20240506-203857 + * IBM OpenAPI Terraform Generator Version: 3.95.2-120e65bc-20240924-152329 */ package mqcloud @@ -29,7 +29,7 @@ func DataSourceIbmMqcloudUser() *schema.Resource { "service_instance_guid": { Type: schema.TypeString, Required: true, - Description: "The GUID that uniquely identifies the MQ on Cloud service instance.", + Description: "The GUID that uniquely identifies the MQaaS service instance.", }, "name": { Type: schema.TypeString, @@ -134,7 +134,7 @@ func dataSourceIbmMqcloudUserRead(context context.Context, d *schema.ResourceDat mapSlice := []map[string]interface{}{} for _, modelItem := range allItems { modelItem := modelItem - modelMap, err := DataSourceIbmMqcloudUserUserDetailsToMap(&modelItem) + modelMap, err := DataSourceIbmMqcloudUserUserDetailsToMap(&modelItem) // #nosec G601 if err != nil { tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_mqcloud_user", "read") return tfErr.GetDiag() diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_user_test.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_user_test.go index 0b7edf6fec..98006d6b0e 100644 --- a/ibm/service/mqcloud/data_source_ibm_mqcloud_user_test.go +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_user_test.go @@ -2,7 +2,7 @@ // Licensed under the Mozilla Public License v2.0 /* - * IBM OpenAPI Terraform Generator Version: 3.90.0-5aad763d-20240506-203857 + * IBM OpenAPI Terraform Generator Version: 3.95.2-120e65bc-20240924-152329 */ package mqcloud_test @@ -23,7 +23,7 @@ import ( func TestAccIbmMqcloudUserDataSourceBasic(t *testing.T) { t.Parallel() - userDetailsServiceInstanceGuid := acc.MqcloudInstanceID + userDetailsServiceInstanceGuid := acc.MqcloudDeploymentID userDetailsName := fmt.Sprintf("tfname%d", acctest.RandIntRange(10, 100)) userDetailsEmail := fmt.Sprintf("tfemail%d@ibm.com", acctest.RandIntRange(10, 100)) diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_virtual_private_endpoint_gateway.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_virtual_private_endpoint_gateway.go new file mode 100644 index 0000000000..b12448a5d9 --- /dev/null +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_virtual_private_endpoint_gateway.go @@ -0,0 +1,109 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +/* + * IBM OpenAPI Terraform Generator Version: 3.96.0-d6dec9d7-20241008-212902 + */ + +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/mqcloud-go-sdk/mqcloudv1" +) + +func DataSourceIbmMqcloudVirtualPrivateEndpointGateway() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIbmMqcloudVirtualPrivateEndpointGatewayRead, + + Schema: map[string]*schema.Schema{ + "service_instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "The GUID that uniquely identifies the MQaaS service instance.", + }, + "virtual_private_endpoint_gateway_guid": { + Type: schema.TypeString, + Required: true, + Description: "The id of the virtual private endpoint gateway.", + }, + "trusted_profile": { + Type: schema.TypeString, + Optional: true, + Description: "The CRN of the trusted profile to assume for this request.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "URL for the details of the virtual private endpoint gateway.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the virtual private endpoint gateway, created by the user.", + }, + "target_crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN of the reserved capacity service instance the user is trying to connect to.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of this virtual privage endpoint.", + }, + }, + } +} + +func dataSourceIbmMqcloudVirtualPrivateEndpointGatewayRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_mqcloud_virtual_private_endpoint_gateway", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + getVirtualPrivateEndpointGatewayOptions := &mqcloudv1.GetVirtualPrivateEndpointGatewayOptions{} + + getVirtualPrivateEndpointGatewayOptions.SetServiceInstanceGuid(d.Get("service_instance_guid").(string)) + getVirtualPrivateEndpointGatewayOptions.SetVirtualPrivateEndpointGatewayGuid(d.Get("virtual_private_endpoint_gateway_guid").(string)) + if _, ok := d.GetOk("trusted_profile"); ok { + getVirtualPrivateEndpointGatewayOptions.SetTrustedProfile(d.Get("trusted_profile").(string)) + } + + virtualPrivateEndpointGatewayDetails, _, err := mqcloudClient.GetVirtualPrivateEndpointGatewayWithContext(context, getVirtualPrivateEndpointGatewayOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetVirtualPrivateEndpointGatewayWithContext failed: %s", err.Error()), "(Data) ibm_mqcloud_virtual_private_endpoint_gateway", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(fmt.Sprintf("%s/%s", *getVirtualPrivateEndpointGatewayOptions.ServiceInstanceGuid, *getVirtualPrivateEndpointGatewayOptions.VirtualPrivateEndpointGatewayGuid)) + + if err = d.Set("href", virtualPrivateEndpointGatewayDetails.Href); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting href: %s", err), "(Data) ibm_mqcloud_virtual_private_endpoint_gateway", "read", "set-href").GetDiag() + } + + if err = d.Set("name", virtualPrivateEndpointGatewayDetails.Name); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting name: %s", err), "(Data) ibm_mqcloud_virtual_private_endpoint_gateway", "read", "set-name").GetDiag() + } + + if err = d.Set("target_crn", virtualPrivateEndpointGatewayDetails.TargetCrn); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting target_crn: %s", err), "(Data) ibm_mqcloud_virtual_private_endpoint_gateway", "read", "set-target_crn").GetDiag() + } + + if err = d.Set("status", virtualPrivateEndpointGatewayDetails.Status); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting status: %s", err), "(Data) ibm_mqcloud_virtual_private_endpoint_gateway", "read", "set-status").GetDiag() + } + + return nil +} diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_virtual_private_endpoint_gateway_test.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_virtual_private_endpoint_gateway_test.go new file mode 100644 index 0000000000..51901087d2 --- /dev/null +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_virtual_private_endpoint_gateway_test.go @@ -0,0 +1,105 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +/* + * IBM OpenAPI Terraform Generator Version: 3.96.0-d6dec9d7-20241008-212902 + */ + +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 TestAccIbmMqcloudVirtualPrivateEndpointGatewayDataSourceBasic(t *testing.T) { + t.Parallel() + virtualPrivateEndpointGatewayDetailsServiceInstanceGuid := acc.MqcloudCapacityID + virtualPrivateEndpointGatewayDetailsName := fmt.Sprintf("tf-name-%d", acctest.RandIntRange(10, 100)) + virtualPrivateEndpointGatewayDetailsTargetCrn := acc.MqCloudVirtualPrivateEndPointTargetCrn + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudVirtualPrivateEndpointGatewayDataSourceConfigBasic(virtualPrivateEndpointGatewayDetailsServiceInstanceGuid, virtualPrivateEndpointGatewayDetailsName, virtualPrivateEndpointGatewayDetailsTargetCrn), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", "service_instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", "virtual_private_endpoint_gateway_guid"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", "href"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", "name"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", "target_crn"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", "status"), + ), + }, + }, + }) +} + +func TestAccIbmMqcloudVirtualPrivateEndpointGatewayDataSourceAllArgs(t *testing.T) { + t.Parallel() + virtualPrivateEndpointGatewayDetailsServiceInstanceGuid := acc.MqcloudCapacityID + virtualPrivateEndpointGatewayDetailsTrustedProfile := acc.MqCloudVirtualPrivateEndPointTrustedProfile + virtualPrivateEndpointGatewayDetailsName := fmt.Sprintf("tf-name-%d", acctest.RandIntRange(10, 100)) + virtualPrivateEndpointGatewayDetailsTargetCrn := acc.MqCloudVirtualPrivateEndPointTargetCrn + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudVirtualPrivateEndpointGatewayDataSourceConfig(virtualPrivateEndpointGatewayDetailsServiceInstanceGuid, virtualPrivateEndpointGatewayDetailsTrustedProfile, virtualPrivateEndpointGatewayDetailsName, virtualPrivateEndpointGatewayDetailsTargetCrn), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", "service_instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", "virtual_private_endpoint_gateway_guid"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", "trusted_profile"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", "href"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", "name"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", "target_crn"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", "status"), + ), + }, + }, + }) +} + +func testAccCheckIbmMqcloudVirtualPrivateEndpointGatewayDataSourceConfigBasic(virtualPrivateEndpointGatewayDetailsServiceInstanceGuid string, virtualPrivateEndpointGatewayDetailsName string, virtualPrivateEndpointGatewayDetailsTargetCrn string) string { + return fmt.Sprintf(` + resource "ibm_mqcloud_virtual_private_endpoint_gateway" "mqcloud_virtual_private_endpoint_gateway_instance" { + service_instance_guid = "%s" + name = "%s" + target_crn = "%s" + } + + data "ibm_mqcloud_virtual_private_endpoint_gateway" "mqcloud_virtual_private_endpoint_gateway_instance" { + service_instance_guid = ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance.service_instance_guid + virtual_private_endpoint_gateway_guid = ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance.virtual_private_endpoint_gateway_guid + trusted_profile = ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance.trusted_profile + } + `, virtualPrivateEndpointGatewayDetailsServiceInstanceGuid, virtualPrivateEndpointGatewayDetailsName, virtualPrivateEndpointGatewayDetailsTargetCrn) +} + +func testAccCheckIbmMqcloudVirtualPrivateEndpointGatewayDataSourceConfig(virtualPrivateEndpointGatewayDetailsServiceInstanceGuid string, virtualPrivateEndpointGatewayDetailsTrustedProfile string, virtualPrivateEndpointGatewayDetailsName string, virtualPrivateEndpointGatewayDetailsTargetCrn string) string { + return fmt.Sprintf(` + resource "ibm_mqcloud_virtual_private_endpoint_gateway" "mqcloud_virtual_private_endpoint_gateway_instance" { + service_instance_guid = "%s" + trusted_profile = "%s" + name = "%s" + target_crn = "%s" + } + + data "ibm_mqcloud_virtual_private_endpoint_gateway" "mqcloud_virtual_private_endpoint_gateway_instance" { + service_instance_guid = ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance.service_instance_guid + virtual_private_endpoint_gateway_guid = ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance.virtual_private_endpoint_gateway_guid + trusted_profile = ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance.trusted_profile + } + `, virtualPrivateEndpointGatewayDetailsServiceInstanceGuid, virtualPrivateEndpointGatewayDetailsTrustedProfile, virtualPrivateEndpointGatewayDetailsName, virtualPrivateEndpointGatewayDetailsTargetCrn) +} diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_virtual_private_endpoint_gateways.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_virtual_private_endpoint_gateways.go new file mode 100644 index 0000000000..cd11a1cefb --- /dev/null +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_virtual_private_endpoint_gateways.go @@ -0,0 +1,150 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +/* + * IBM OpenAPI Terraform Generator Version: 3.96.0-d6dec9d7-20241008-212902 + */ + +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 DataSourceIbmMqcloudVirtualPrivateEndpointGateways() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIbmMqcloudVirtualPrivateEndpointGatewaysRead, + + Schema: map[string]*schema.Schema{ + "service_instance_guid": { + Type: schema.TypeString, + Required: true, + Description: "The GUID that uniquely identifies the MQaaS service instance.", + }, + "trusted_profile": { + Type: schema.TypeString, + Optional: true, + Description: "The CRN of the trusted profile to assume for this request.", + }, + "name": { + Type: schema.TypeString, + Optional: true, + Description: "The name of the virtual private endpoint gateway, created by the user.", + }, + "virtual_private_endpoint_gateways": { + Type: schema.TypeList, + Computed: true, + Description: "List of virtual private endpoint gateways.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "URL for the details of the virtual private endpoint gateway.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the virtual private endpoint gateway which was allocated on creation.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the virtual private endpoint gateway, created by the user.", + }, + "target_crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN of the reserved capacity service instance the user is trying to connect to.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of this virtual privage endpoint.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIbmMqcloudVirtualPrivateEndpointGatewaysRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_mqcloud_virtual_private_endpoint_gateways", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + listVirtualPrivateEndpointGatewaysOptions := &mqcloudv1.ListVirtualPrivateEndpointGatewaysOptions{} + + listVirtualPrivateEndpointGatewaysOptions.SetServiceInstanceGuid(d.Get("service_instance_guid").(string)) + if _, ok := d.GetOk("trusted_profile"); ok { + listVirtualPrivateEndpointGatewaysOptions.SetTrustedProfile(d.Get("trusted_profile").(string)) + } + + var pager *mqcloudv1.VirtualPrivateEndpointGatewaysPager + pager, err = mqcloudClient.NewVirtualPrivateEndpointGatewaysPager(listVirtualPrivateEndpointGatewaysOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_mqcloud_virtual_private_endpoint_gateways", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + allItems, err := pager.GetAll() + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("VirtualPrivateEndpointGatewaysPager.GetAll() failed %s", err), "(Data) ibm_mqcloud_virtual_private_endpoint_gateways", "read") + log.Printf("[DEBUG] %s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + var name string + + if v, ok := d.GetOk("name"); ok { + name = v.(string) + d.SetId(name) + } else { + d.SetId(dataSourceIbmMqcloudVirtualPrivateEndpointGatewaysID(d)) + } + + mapSlice := []map[string]interface{}{} + for _, modelItem := range allItems { + modelMap, err := DataSourceIbmMqcloudVirtualPrivateEndpointGatewaysVirtualPrivateEndpointGatewayDetailsToMap(&modelItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_mqcloud_virtual_private_endpoint_gateways", "read", "VirtualPrivateEndpointsGateways-to-map").GetDiag() + } + mapSlice = append(mapSlice, modelMap) + } + + if err = d.Set("virtual_private_endpoint_gateways", mapSlice); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting virtual_private_endpoint_gateways %s", err), "(Data) ibm_mqcloud_virtual_private_endpoint_gateways", "read", "virtual_private_endpoint_gateways-set").GetDiag() + } + + return nil +} + +// dataSourceIbmMqcloudVirtualPrivateEndpointGatewaysID returns a reasonable ID for the list. +func dataSourceIbmMqcloudVirtualPrivateEndpointGatewaysID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func DataSourceIbmMqcloudVirtualPrivateEndpointGatewaysVirtualPrivateEndpointGatewayDetailsToMap(model *mqcloudv1.VirtualPrivateEndpointGatewayDetails) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["id"] = *model.ID + modelMap["name"] = *model.Name + modelMap["target_crn"] = *model.TargetCrn + modelMap["status"] = *model.Status + return modelMap, nil +} diff --git a/ibm/service/mqcloud/data_source_ibm_mqcloud_virtual_private_endpoint_gateways_test.go b/ibm/service/mqcloud/data_source_ibm_mqcloud_virtual_private_endpoint_gateways_test.go new file mode 100644 index 0000000000..221a856c87 --- /dev/null +++ b/ibm/service/mqcloud/data_source_ibm_mqcloud_virtual_private_endpoint_gateways_test.go @@ -0,0 +1,134 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +/* + * IBM OpenAPI Terraform Generator Version: 3.96.0-d6dec9d7-20241008-212902 + */ + +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" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/mqcloud" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/mqcloud-go-sdk/mqcloudv1" + "github.com/stretchr/testify/assert" +) + +func TestAccIbmMqcloudVirtualPrivateEndpointGatewaysDataSourceBasic(t *testing.T) { + t.Parallel() + virtualPrivateEndpointGatewayDetailsServiceInstanceGuid := acc.MqcloudCapacityID + virtualPrivateEndpointGatewayDetailsName := fmt.Sprintf("tf-name-%d", acctest.RandIntRange(10, 100)) + virtualPrivateEndpointGatewayDetailsTargetCrn := acc.MqCloudVirtualPrivateEndPointTargetCrn + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudVirtualPrivateEndpointGatewaysDataSourceConfigBasic(virtualPrivateEndpointGatewayDetailsServiceInstanceGuid, virtualPrivateEndpointGatewayDetailsName, virtualPrivateEndpointGatewayDetailsTargetCrn), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateways.mqcloud_virtual_private_endpoint_gateways_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateways.mqcloud_virtual_private_endpoint_gateways_instance", "service_instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateways.mqcloud_virtual_private_endpoint_gateways_instance", "virtual_private_endpoint_gateways.#"), + resource.TestCheckResourceAttr("data.ibm_mqcloud_virtual_private_endpoint_gateways.mqcloud_virtual_private_endpoint_gateways_instance", "virtual_private_endpoint_gateways.0.name", virtualPrivateEndpointGatewayDetailsName), + resource.TestCheckResourceAttr("data.ibm_mqcloud_virtual_private_endpoint_gateways.mqcloud_virtual_private_endpoint_gateways_instance", "virtual_private_endpoint_gateways.0.target_crn", virtualPrivateEndpointGatewayDetailsTargetCrn), + ), + }, + }, + }) +} + +func TestAccIbmMqcloudVirtualPrivateEndpointGatewaysDataSourceAllArgs(t *testing.T) { + t.Parallel() + virtualPrivateEndpointGatewayDetailsServiceInstanceGuid := acc.MqcloudCapacityID + virtualPrivateEndpointGatewayDetailsTrustedProfile := acc.MqCloudVirtualPrivateEndPointTrustedProfile + virtualPrivateEndpointGatewayDetailsName := fmt.Sprintf("tf-name-%d", acctest.RandIntRange(10, 100)) + virtualPrivateEndpointGatewayDetailsTargetCrn := acc.MqCloudVirtualPrivateEndPointTargetCrn + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudVirtualPrivateEndpointGatewaysDataSourceConfig(virtualPrivateEndpointGatewayDetailsServiceInstanceGuid, virtualPrivateEndpointGatewayDetailsTrustedProfile, virtualPrivateEndpointGatewayDetailsName, virtualPrivateEndpointGatewayDetailsTargetCrn), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateways.mqcloud_virtual_private_endpoint_gateways_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateways.mqcloud_virtual_private_endpoint_gateways_instance", "service_instance_guid"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateways.mqcloud_virtual_private_endpoint_gateways_instance", "trusted_profile"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateways.mqcloud_virtual_private_endpoint_gateways_instance", "name"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateways.mqcloud_virtual_private_endpoint_gateways_instance", "virtual_private_endpoint_gateways.#"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateways.mqcloud_virtual_private_endpoint_gateways_instance", "virtual_private_endpoint_gateways.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateways.mqcloud_virtual_private_endpoint_gateways_instance", "virtual_private_endpoint_gateways.0.id"), + resource.TestCheckResourceAttr("data.ibm_mqcloud_virtual_private_endpoint_gateways.mqcloud_virtual_private_endpoint_gateways_instance", "virtual_private_endpoint_gateways.0.name", virtualPrivateEndpointGatewayDetailsName), + resource.TestCheckResourceAttr("data.ibm_mqcloud_virtual_private_endpoint_gateways.mqcloud_virtual_private_endpoint_gateways_instance", "virtual_private_endpoint_gateways.0.target_crn", virtualPrivateEndpointGatewayDetailsTargetCrn), + resource.TestCheckResourceAttrSet("data.ibm_mqcloud_virtual_private_endpoint_gateways.mqcloud_virtual_private_endpoint_gateways_instance", "virtual_private_endpoint_gateways.0.status"), + ), + }, + }, + }) +} + +func testAccCheckIbmMqcloudVirtualPrivateEndpointGatewaysDataSourceConfigBasic(virtualPrivateEndpointGatewayDetailsServiceInstanceGuid string, virtualPrivateEndpointGatewayDetailsName string, virtualPrivateEndpointGatewayDetailsTargetCrn string) string { + return fmt.Sprintf(` + resource "ibm_mqcloud_virtual_private_endpoint_gateway" "mqcloud_virtual_private_endpoint_gateway_instance" { + service_instance_guid = "%s" + name = "%s" + target_crn = "%s" + } + + data "ibm_mqcloud_virtual_private_endpoint_gateways" "mqcloud_virtual_private_endpoint_gateways_instance" { + service_instance_guid = ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance.service_instance_guid + trusted_profile = ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance.trusted_profile + name = ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance.name + } + `, virtualPrivateEndpointGatewayDetailsServiceInstanceGuid, virtualPrivateEndpointGatewayDetailsName, virtualPrivateEndpointGatewayDetailsTargetCrn) +} + +func testAccCheckIbmMqcloudVirtualPrivateEndpointGatewaysDataSourceConfig(virtualPrivateEndpointGatewayDetailsServiceInstanceGuid string, virtualPrivateEndpointGatewayDetailsTrustedProfile string, virtualPrivateEndpointGatewayDetailsName string, virtualPrivateEndpointGatewayDetailsTargetCrn string) string { + return fmt.Sprintf(` + resource "ibm_mqcloud_virtual_private_endpoint_gateway" "mqcloud_virtual_private_endpoint_gateway_instance" { + service_instance_guid = "%s" + trusted_profile = "%s" + name = "%s" + target_crn = "%s" + } + + data "ibm_mqcloud_virtual_private_endpoint_gateways" "mqcloud_virtual_private_endpoint_gateways_instance" { + service_instance_guid = ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance.service_instance_guid + trusted_profile = ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance.trusted_profile + name = ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance.name + } + `, virtualPrivateEndpointGatewayDetailsServiceInstanceGuid, virtualPrivateEndpointGatewayDetailsTrustedProfile, virtualPrivateEndpointGatewayDetailsName, virtualPrivateEndpointGatewayDetailsTargetCrn) +} + +func TestDataSourceIbmMqcloudVirtualPrivateEndpointGatewaysVirtualPrivateEndpointGatewayDetailsToMap(t *testing.T) { + t.Parallel() + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["href"] = "testString" + model["id"] = "testString" + model["name"] = "testString" + model["target_crn"] = "testString" + model["status"] = "testString" + + assert.Equal(t, result, model) + } + + model := new(mqcloudv1.VirtualPrivateEndpointGatewayDetails) + model.Href = core.StringPtr("testString") + model.ID = core.StringPtr("testString") + model.Name = core.StringPtr("testString") + model.TargetCrn = core.StringPtr("testString") + model.Status = core.StringPtr("testString") + + result, err := mqcloud.DataSourceIbmMqcloudVirtualPrivateEndpointGatewaysVirtualPrivateEndpointGatewayDetailsToMap(model) + assert.Nil(t, err) + checkResult(result) +} diff --git a/ibm/service/mqcloud/resource_ibm_mqcloud_application.go b/ibm/service/mqcloud/resource_ibm_mqcloud_application.go index fb339ce2fa..6c0240a998 100644 --- a/ibm/service/mqcloud/resource_ibm_mqcloud_application.go +++ b/ibm/service/mqcloud/resource_ibm_mqcloud_application.go @@ -2,7 +2,7 @@ // Licensed under the Mozilla Public License v2.0 /* - * IBM OpenAPI Terraform Generator Version: 3.90.0-5aad763d-20240506-203857 + * IBM OpenAPI Terraform Generator Version: 3.95.2-120e65bc-20240924-152329 */ package mqcloud @@ -34,7 +34,7 @@ func ResourceIbmMqcloudApplication() *schema.Resource { 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.", + Description: "The GUID that uniquely identifies the MQaaS service instance.", }, "name": { Type: schema.TypeString, diff --git a/ibm/service/mqcloud/resource_ibm_mqcloud_application_test.go b/ibm/service/mqcloud/resource_ibm_mqcloud_application_test.go index de132abe23..281e230f11 100644 --- a/ibm/service/mqcloud/resource_ibm_mqcloud_application_test.go +++ b/ibm/service/mqcloud/resource_ibm_mqcloud_application_test.go @@ -19,7 +19,7 @@ import ( func TestAccIbmMqcloudApplicationBasic(t *testing.T) { t.Parallel() var conf mqcloudv1.ApplicationDetails - serviceInstanceGuid := acc.MqcloudInstanceID + serviceInstanceGuid := acc.MqcloudDeploymentID name := "appbasic" resource.Test(t, resource.TestCase{ diff --git a/ibm/service/mqcloud/resource_ibm_mqcloud_keystore_certificate.go b/ibm/service/mqcloud/resource_ibm_mqcloud_keystore_certificate.go index 7c0b03bac6..208d45be16 100644 --- a/ibm/service/mqcloud/resource_ibm_mqcloud_keystore_certificate.go +++ b/ibm/service/mqcloud/resource_ibm_mqcloud_keystore_certificate.go @@ -2,7 +2,7 @@ // Licensed under the Mozilla Public License v2.0 /* - * IBM OpenAPI Terraform Generator Version: 3.90.0-5aad763d-20240506-203857 + * IBM OpenAPI Terraform Generator Version: 3.95.2-120e65bc-20240924-152329 */ package mqcloud @@ -39,7 +39,7 @@ func ResourceIbmMqcloudKeystoreCertificate() *schema.Resource { 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.", + Description: "The GUID that uniquely identifies the MQaaS service instance.", }, "queue_manager_id": { Type: schema.TypeString, @@ -143,6 +143,7 @@ func ResourceIbmMqcloudKeystoreCertificate() *schema.Resource { "name": { Type: schema.TypeString, Optional: true, + Computed: true, Description: "The name of the channel.", }, }, @@ -521,7 +522,7 @@ func ResourceIbmMqcloudKeystoreCertificateChannelsDetailsToMap(model *mqcloudv1. channels := []map[string]interface{}{} for _, channelsItem := range model.Channels { channelsItem := channelsItem - channelsItemMap, err := ResourceIbmMqcloudKeystoreCertificateChannelDetailsToMap(&channelsItem) + channelsItemMap, err := ResourceIbmMqcloudKeystoreCertificateChannelDetailsToMap(&channelsItem) // #nosec G601 if err != nil { return modelMap, err } diff --git a/ibm/service/mqcloud/resource_ibm_mqcloud_keystore_certificate_test.go b/ibm/service/mqcloud/resource_ibm_mqcloud_keystore_certificate_test.go index 6dc08c7ff1..b4f480a6e8 100644 --- a/ibm/service/mqcloud/resource_ibm_mqcloud_keystore_certificate_test.go +++ b/ibm/service/mqcloud/resource_ibm_mqcloud_keystore_certificate_test.go @@ -21,15 +21,16 @@ import ( ) func TestAccIbmMqcloudKeystoreCertificateBasic(t *testing.T) { - t.Parallel() var conf mqcloudv1.KeyStoreCertificateDetails - serviceInstanceGuid := acc.MqcloudInstanceID + serviceInstanceGuid := acc.MqcloudDeploymentID 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) }, + PreCheck: func() { + acc.TestAccPreCheckMqcloud(t) + }, Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIbmMqcloudKeystoreCertificateDestroy, Steps: []resource.TestStep{ diff --git a/ibm/service/mqcloud/resource_ibm_mqcloud_queue_manager.go b/ibm/service/mqcloud/resource_ibm_mqcloud_queue_manager.go index f0509d3fa0..46c954af7c 100644 --- a/ibm/service/mqcloud/resource_ibm_mqcloud_queue_manager.go +++ b/ibm/service/mqcloud/resource_ibm_mqcloud_queue_manager.go @@ -2,7 +2,7 @@ // Licensed under the Mozilla Public License v2.0 /* - * IBM OpenAPI Terraform Generator Version: 3.90.0-5aad763d-20240506-203857 + * IBM OpenAPI Terraform Generator Version: 3.95.2-120e65bc-20240924-152329 */ package mqcloud @@ -43,7 +43,7 @@ func ResourceIbmMqcloudQueueManager() *schema.Resource { 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.", + Description: "The GUID that uniquely identifies the MQaaS service instance.", }, "name": { Type: schema.TypeString, @@ -232,6 +232,7 @@ func resourceIbmMqcloudQueueManagerCreate(context context.Context, d *schema.Res } d.SetId(fmt.Sprintf("%s/%s", *createQueueManagerOptions.ServiceInstanceGuid, *queueManagerTaskStatus.QueueManagerID)) + if waitForQmStatus { _, err = waitForQmStatusUpdate(context, d, meta) if err != nil { @@ -274,7 +275,6 @@ func resourceIbmMqcloudQueueManagerRead(context context.Context, d *schema.Resou return nil }) - if err != nil { if response != nil && response.StatusCode == 404 { d.SetId("") diff --git a/ibm/service/mqcloud/resource_ibm_mqcloud_queue_manager_test.go b/ibm/service/mqcloud/resource_ibm_mqcloud_queue_manager_test.go index 8511943a31..6667e40693 100644 --- a/ibm/service/mqcloud/resource_ibm_mqcloud_queue_manager_test.go +++ b/ibm/service/mqcloud/resource_ibm_mqcloud_queue_manager_test.go @@ -20,7 +20,7 @@ import ( func TestAccIbmMqcloudQueueManagerBasic(t *testing.T) { t.Parallel() var conf mqcloudv1.QueueManagerDetails - serviceInstanceGuid := acc.MqcloudInstanceID + serviceInstanceGuid := acc.MqcloudDeploymentID name := fmt.Sprintf("tf_queue_manager_basic%d", acctest.RandIntRange(10, 100)) location := acc.MqCloudQueueManagerLocation size := "xsmall" @@ -47,7 +47,7 @@ func TestAccIbmMqcloudQueueManagerBasic(t *testing.T) { func TestAccIbmMqcloudQueueManagerAllArgs(t *testing.T) { t.Parallel() var conf mqcloudv1.QueueManagerDetails - serviceInstanceGuid := acc.MqcloudInstanceID + serviceInstanceGuid := acc.MqcloudDeploymentID name := fmt.Sprintf("tf_queue_manager_allargs%d", acctest.RandIntRange(10, 100)) displayName := name location := acc.MqCloudQueueManagerLocation diff --git a/ibm/service/mqcloud/resource_ibm_mqcloud_truststore_certificate.go b/ibm/service/mqcloud/resource_ibm_mqcloud_truststore_certificate.go index 5addded2cb..58f352c0ff 100644 --- a/ibm/service/mqcloud/resource_ibm_mqcloud_truststore_certificate.go +++ b/ibm/service/mqcloud/resource_ibm_mqcloud_truststore_certificate.go @@ -2,7 +2,7 @@ // Licensed under the Mozilla Public License v2.0 /* - * IBM OpenAPI Terraform Generator Version: 3.90.0-5aad763d-20240506-203857 + * IBM OpenAPI Terraform Generator Version: 3.95.2-120e65bc-20240924-152329 */ package mqcloud @@ -37,7 +37,7 @@ func ResourceIbmMqcloudTruststoreCertificate() *schema.Resource { 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.", + Description: "The GUID that uniquely identifies the MQaaS service instance.", }, "queue_manager_id": { Type: schema.TypeString, diff --git a/ibm/service/mqcloud/resource_ibm_mqcloud_truststore_certificate_test.go b/ibm/service/mqcloud/resource_ibm_mqcloud_truststore_certificate_test.go index 6c8e2e70ba..eb17f3f3a0 100644 --- a/ibm/service/mqcloud/resource_ibm_mqcloud_truststore_certificate_test.go +++ b/ibm/service/mqcloud/resource_ibm_mqcloud_truststore_certificate_test.go @@ -18,15 +18,16 @@ import ( ) func TestAccIbmMqcloudTruststoreCertificateBasic(t *testing.T) { - t.Parallel() var conf mqcloudv1.TrustStoreCertificateDetails - serviceInstanceGuid := acc.MqcloudInstanceID + serviceInstanceGuid := acc.MqcloudDeploymentID 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) }, + PreCheck: func() { + acc.TestAccPreCheckMqcloud(t) + }, Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIbmMqcloudTruststoreCertificateDestroy, Steps: []resource.TestStep{ diff --git a/ibm/service/mqcloud/resource_ibm_mqcloud_user.go b/ibm/service/mqcloud/resource_ibm_mqcloud_user.go index 4fe023ec38..92260b03b9 100644 --- a/ibm/service/mqcloud/resource_ibm_mqcloud_user.go +++ b/ibm/service/mqcloud/resource_ibm_mqcloud_user.go @@ -2,7 +2,7 @@ // Licensed under the Mozilla Public License v2.0 /* - * IBM OpenAPI Terraform Generator Version: 3.90.0-5aad763d-20240506-203857 + * IBM OpenAPI Terraform Generator Version: 3.95.2-120e65bc-20240924-152329 */ package mqcloud @@ -34,7 +34,7 @@ func ResourceIbmMqcloudUser() *schema.Resource { 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.", + Description: "The GUID that uniquely identifies the MQaaS service instance.", }, "name": { Type: schema.TypeString, @@ -165,7 +165,6 @@ func resourceIbmMqcloudUserRead(context context.Context, d *schema.ResourceData, err = fmt.Errorf("Error setting service_instance_guid: %s", err) return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_mqcloud_user", "read", "set-service_instance_guid").GetDiag() } - if err = d.Set("name", userDetails.Name); err != nil { err = fmt.Errorf("Error setting name: %s", err) return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_mqcloud_user", "read", "set-name").GetDiag() diff --git a/ibm/service/mqcloud/resource_ibm_mqcloud_user_test.go b/ibm/service/mqcloud/resource_ibm_mqcloud_user_test.go index 745a385893..e732d993a9 100644 --- a/ibm/service/mqcloud/resource_ibm_mqcloud_user_test.go +++ b/ibm/service/mqcloud/resource_ibm_mqcloud_user_test.go @@ -20,7 +20,7 @@ import ( func TestAccIbmMqcloudUserBasic(t *testing.T) { t.Parallel() var conf mqcloudv1.UserDetails - serviceInstanceGuid := acc.MqcloudInstanceID + serviceInstanceGuid := acc.MqcloudDeploymentID name := fmt.Sprintf("tfname%d", acctest.RandIntRange(10, 100)) email := fmt.Sprintf("tfemail%d@ibm.com", acctest.RandIntRange(10, 100)) diff --git a/ibm/service/mqcloud/resource_ibm_mqcloud_virtual_private_endpoint_gateway.go b/ibm/service/mqcloud/resource_ibm_mqcloud_virtual_private_endpoint_gateway.go new file mode 100644 index 0000000000..11dd01035c --- /dev/null +++ b/ibm/service/mqcloud/resource_ibm_mqcloud_virtual_private_endpoint_gateway.go @@ -0,0 +1,254 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +/* + * IBM OpenAPI Terraform Generator Version: 3.96.0-d6dec9d7-20241008-212902 + */ + +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 ResourceIbmMqcloudVirtualPrivateEndpointGateway() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIbmMqcloudVirtualPrivateEndpointGatewayCreate, + ReadContext: resourceIbmMqcloudVirtualPrivateEndpointGatewayRead, + DeleteContext: resourceIbmMqcloudVirtualPrivateEndpointGatewayDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "service_instance_guid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_mqcloud_virtual_private_endpoint_gateway", "service_instance_guid"), + Description: "The GUID that uniquely identifies the MQaaS service instance.", + }, + "trusted_profile": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_mqcloud_virtual_private_endpoint_gateway", "trusted_profile"), + Description: "The CRN of the trusted profile to assume for this request.", + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_mqcloud_virtual_private_endpoint_gateway", "name"), + Description: "The name of the virtual private endpoint gateway, created by the user.", + }, + "target_crn": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_mqcloud_virtual_private_endpoint_gateway", "target_crn"), + Description: "The CRN of the reserved capacity service instance the user is trying to connect to.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "URL for the details of the virtual private endpoint gateway.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of this virtual privage endpoint.", + }, + "virtual_private_endpoint_gateway_guid": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the virtual private endpoint gateway which was allocated on creation.", + }, + }, + } +} + +func ResourceIbmMqcloudVirtualPrivateEndpointGatewayValidator() *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: "trusted_profile", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^crn:v[0-9]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]*:([a-z]\/[a-z0-9-]+)?:[a-z0-9-]*:[a-z0-9-]*:[a-zA-Z0-9-_\.\/]*$|^crn:\[\.\.\.\]$`, + MinValueLength: 9, + MaxValueLength: 512, + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-z]|[a-z][-a-z0-9]*[a-z0-9]$`, + MinValueLength: 1, + MaxValueLength: 63, + }, + validate.ValidateSchema{ + Identifier: "target_crn", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^crn:v[0-9]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]*:([a-z]\/[a-z0-9-]+)?:[a-z0-9-]*:[a-z0-9-]*:[a-zA-Z0-9-_\.\/]*$|^crn:\[\.\.\.\]$`, + MinValueLength: 9, + MaxValueLength: 512, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_mqcloud_virtual_private_endpoint_gateway", Schema: validateSchema} + return &resourceValidator +} + +func resourceIbmMqcloudVirtualPrivateEndpointGatewayCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_mqcloud_virtual_private_endpoint_gateway", "create", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + err = checkSIPlan(d, meta) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Create Virtual Private Endpoint Gateway failed: %s", err.Error()), "ibm_mqcloud_virtual_private_endpoint_gateway", "create") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + createVirtualPrivateEndpointGatewayOptions := &mqcloudv1.CreateVirtualPrivateEndpointGatewayOptions{} + + createVirtualPrivateEndpointGatewayOptions.SetServiceInstanceGuid(d.Get("service_instance_guid").(string)) + createVirtualPrivateEndpointGatewayOptions.SetName(d.Get("name").(string)) + createVirtualPrivateEndpointGatewayOptions.SetTargetCrn(d.Get("target_crn").(string)) + if _, ok := d.GetOk("trusted_profile"); ok { + createVirtualPrivateEndpointGatewayOptions.SetTrustedProfile(d.Get("trusted_profile").(string)) + } + + virtualPrivateEndpointGatewayDetails, _, err := mqcloudClient.CreateVirtualPrivateEndpointGatewayWithContext(context, createVirtualPrivateEndpointGatewayOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("CreateVirtualPrivateEndpointGatewayWithContext failed: %s", err.Error()), "ibm_mqcloud_virtual_private_endpoint_gateway", "create") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(fmt.Sprintf("%s/%s", *createVirtualPrivateEndpointGatewayOptions.ServiceInstanceGuid, *virtualPrivateEndpointGatewayDetails.ID)) + + return resourceIbmMqcloudVirtualPrivateEndpointGatewayRead(context, d, meta) +} + +func resourceIbmMqcloudVirtualPrivateEndpointGatewayRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_mqcloud_virtual_private_endpoint_gateway", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + getVirtualPrivateEndpointGatewayOptions := &mqcloudv1.GetVirtualPrivateEndpointGatewayOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_mqcloud_virtual_private_endpoint_gateway", "read", "sep-id-parts").GetDiag() + } + + getVirtualPrivateEndpointGatewayOptions.SetServiceInstanceGuid(parts[0]) + getVirtualPrivateEndpointGatewayOptions.SetVirtualPrivateEndpointGatewayGuid(parts[1]) + if _, ok := d.GetOk("trusted_profile"); ok { + getVirtualPrivateEndpointGatewayOptions.SetTrustedProfile(d.Get("trusted_profile").(string)) + } + + virtualPrivateEndpointGatewayDetails, response, err := mqcloudClient.GetVirtualPrivateEndpointGatewayWithContext(context, getVirtualPrivateEndpointGatewayOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetVirtualPrivateEndpointGatewayWithContext failed: %s", err.Error()), "ibm_mqcloud_virtual_private_endpoint_gateway", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + if err = d.Set("name", virtualPrivateEndpointGatewayDetails.Name); err != nil { + err = fmt.Errorf("Error setting name: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_mqcloud_virtual_private_endpoint_gateway", "read", "set-name").GetDiag() + } + if err = d.Set("target_crn", virtualPrivateEndpointGatewayDetails.TargetCrn); err != nil { + err = fmt.Errorf("Error setting target_crn: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_mqcloud_virtual_private_endpoint_gateway", "read", "set-target_crn").GetDiag() + } + if err = d.Set("href", virtualPrivateEndpointGatewayDetails.Href); err != nil { + err = fmt.Errorf("Error setting href: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_mqcloud_virtual_private_endpoint_gateway", "read", "set-href").GetDiag() + } + if err = d.Set("status", virtualPrivateEndpointGatewayDetails.Status); err != nil { + err = fmt.Errorf("Error setting status: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_mqcloud_virtual_private_endpoint_gateway", "read", "set-status").GetDiag() + } + if err = d.Set("virtual_private_endpoint_gateway_guid", virtualPrivateEndpointGatewayDetails.ID); err != nil { + err = fmt.Errorf("Error setting virtual_private_endpoint_gateway_guid: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_mqcloud_virtual_private_endpoint_gateway", "read", "set-virtual_private_endpoint_gateway_guid").GetDiag() + } + + return nil +} + +func resourceIbmMqcloudVirtualPrivateEndpointGatewayDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + mqcloudClient, err := meta.(conns.ClientSession).MqcloudV1() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_mqcloud_virtual_private_endpoint_gateway", "delete", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + err = checkSIPlan(d, meta) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Delete Virtual Private Endpoint Gateway failed: %s", err.Error()), "ibm_mqcloud_virtual_private_endpoint_gateway", "delete") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + deleteVirtualPrivateEndpointGatewayOptions := &mqcloudv1.DeleteVirtualPrivateEndpointGatewayOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_mqcloud_virtual_private_endpoint_gateway", "delete", "sep-id-parts").GetDiag() + } + + deleteVirtualPrivateEndpointGatewayOptions.SetServiceInstanceGuid(parts[0]) + deleteVirtualPrivateEndpointGatewayOptions.SetVirtualPrivateEndpointGatewayGuid(parts[1]) + if _, ok := d.GetOk("trusted_profile"); ok { + deleteVirtualPrivateEndpointGatewayOptions.SetTrustedProfile(d.Get("trusted_profile").(string)) + } + + _, err = mqcloudClient.DeleteVirtualPrivateEndpointGatewayWithContext(context, deleteVirtualPrivateEndpointGatewayOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("DeleteVirtualPrivateEndpointGatewayWithContext failed: %s", err.Error()), "ibm_mqcloud_virtual_private_endpoint_gateway", "delete") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId("") + + return nil +} diff --git a/ibm/service/mqcloud/resource_ibm_mqcloud_virtual_private_endpoint_gateway_test.go b/ibm/service/mqcloud/resource_ibm_mqcloud_virtual_private_endpoint_gateway_test.go new file mode 100644 index 0000000000..5c980cf794 --- /dev/null +++ b/ibm/service/mqcloud/resource_ibm_mqcloud_virtual_private_endpoint_gateway_test.go @@ -0,0 +1,163 @@ +// Copyright IBM Corp. 2024 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 TestAccIbmMqcloudVirtualPrivateEndpointGatewayBasic(t *testing.T) { + t.Parallel() + var conf mqcloudv1.VirtualPrivateEndpointGatewayDetails + serviceInstanceGuid := acc.MqcloudCapacityID + name := fmt.Sprintf("tf-name-%d", acctest.RandIntRange(10, 100)) + targetCrn := acc.MqCloudVirtualPrivateEndPointTargetCrn + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckMqcloud(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmMqcloudVirtualPrivateEndpointGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudVirtualPrivateEndpointGatewayConfigBasic(serviceInstanceGuid, name, targetCrn), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmMqcloudVirtualPrivateEndpointGatewayExists("ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", conf), + resource.TestCheckResourceAttr("ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", "service_instance_guid", serviceInstanceGuid), + resource.TestCheckResourceAttr("ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", "name", name), + resource.TestCheckResourceAttr("ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", "target_crn", targetCrn), + ), + }, + }, + }) +} + +func TestAccIbmMqcloudVirtualPrivateEndpointGatewayAllArgs(t *testing.T) { + t.Parallel() + var conf mqcloudv1.VirtualPrivateEndpointGatewayDetails + serviceInstanceGuid := acc.MqcloudCapacityID + trustedProfile := acc.MqCloudVirtualPrivateEndPointTrustedProfile + name := fmt.Sprintf("tf-name-%d", acctest.RandIntRange(10, 100)) + targetCrn := acc.MqCloudVirtualPrivateEndPointTargetCrn + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmMqcloudVirtualPrivateEndpointGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmMqcloudVirtualPrivateEndpointGatewayConfig(serviceInstanceGuid, trustedProfile, name, targetCrn), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmMqcloudVirtualPrivateEndpointGatewayExists("ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", conf), + resource.TestCheckResourceAttr("ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", "service_instance_guid", serviceInstanceGuid), + resource.TestCheckResourceAttr("ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", "trusted_profile", trustedProfile), + resource.TestCheckResourceAttr("ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", "name", name), + resource.TestCheckResourceAttr("ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", "target_crn", targetCrn), + ), + }, + { + ResourceName: "ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"trusted_profile", "service_instance_guid"}, + }, + }, + }) +} + +func testAccCheckIbmMqcloudVirtualPrivateEndpointGatewayConfigBasic(serviceInstanceGuid string, name string, targetCrn string) string { + return fmt.Sprintf(` + resource "ibm_mqcloud_virtual_private_endpoint_gateway" "mqcloud_virtual_private_endpoint_gateway_instance" { + service_instance_guid = "%s" + name = "%s" + target_crn = "%s" + } + `, serviceInstanceGuid, name, targetCrn) +} + +func testAccCheckIbmMqcloudVirtualPrivateEndpointGatewayConfig(serviceInstanceGuid string, trustedProfile string, name string, targetCrn string) string { + return fmt.Sprintf(` + + resource "ibm_mqcloud_virtual_private_endpoint_gateway" "mqcloud_virtual_private_endpoint_gateway_instance" { + service_instance_guid = "%s" + trusted_profile = "%s" + name = "%s" + target_crn = "%s" + } + `, serviceInstanceGuid, trustedProfile, name, targetCrn) +} + +func testAccCheckIbmMqcloudVirtualPrivateEndpointGatewayExists(n string, obj mqcloudv1.VirtualPrivateEndpointGatewayDetails) 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 + } + + getVirtualPrivateEndpointGatewayOptions := &mqcloudv1.GetVirtualPrivateEndpointGatewayOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getVirtualPrivateEndpointGatewayOptions.SetServiceInstanceGuid(parts[0]) + getVirtualPrivateEndpointGatewayOptions.SetVirtualPrivateEndpointGatewayGuid(parts[1]) + + virtualPrivateEndpointGatewayDetails, _, err := mqcloudClient.GetVirtualPrivateEndpointGateway(getVirtualPrivateEndpointGatewayOptions) + if err != nil { + return err + } + + obj = *virtualPrivateEndpointGatewayDetails + return nil + } +} + +func testAccCheckIbmMqcloudVirtualPrivateEndpointGatewayDestroy(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_virtual_private_endpoint_gateway" { + continue + } + + getVirtualPrivateEndpointGatewayOptions := &mqcloudv1.GetVirtualPrivateEndpointGatewayOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getVirtualPrivateEndpointGatewayOptions.SetServiceInstanceGuid(parts[0]) + getVirtualPrivateEndpointGatewayOptions.SetVirtualPrivateEndpointGatewayGuid(parts[1]) + + // Try to find the key + _, response, err := mqcloudClient.GetVirtualPrivateEndpointGateway(getVirtualPrivateEndpointGatewayOptions) + + if err == nil { + return fmt.Errorf("mqcloud_virtual_private_endpoint_gateway still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for mqcloud_virtual_private_endpoint_gateway (%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 index b904228ea7..fe2222b387 100644 --- a/ibm/service/mqcloud/utils.go +++ b/ibm/service/mqcloud/utils.go @@ -32,6 +32,8 @@ const qmCreating = "initializing" const isQueueManagerDeleting = "true" const isQueueManagerDeleteDone = "true" const reservedDeploymentPlan = "reserved-deployment" +const reservedCapacityPlan = "reserved-capacity" +const reservedCapacitySubscriptionPlan = "reserved-capacity-subscription" const enforceReservedDeploymentPlan = true // change to false for testing in IKS clusters. // waitForQmStatusUpdate waits for Queue Manager to be in running state @@ -213,8 +215,8 @@ func fetchServicePlan(meta interface{}, instanceID string) (string, error) { } func handlePlanCheck(plan string, instanceID string) error { - if !strings.Contains(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) + if !strings.Contains(plan, reservedDeploymentPlan) && !strings.Contains(plan, reservedCapacityPlan) && !strings.Contains(plan, reservedCapacitySubscriptionPlan) { + return fmt.Errorf("[ERROR] Terraform is only supported for Reserved Deployment, Reserved Capacity, and Reserved Capacity Subscription Plans. Your Service Plan is: %s for the instance %s", plan, instanceID) } return nil } diff --git a/ibm/service/mqcloud/utils_test.go b/ibm/service/mqcloud/utils_test.go index d91b649e39..402fff91f4 100644 --- a/ibm/service/mqcloud/utils_test.go +++ b/ibm/service/mqcloud/utils_test.go @@ -92,7 +92,7 @@ func TestHandlePlanCheck(t *testing.T) { {"reserved-deployment", "123", false, ""}, // Test with non-matching plan - {"Basic_Plan", "123", true, "[ERROR] Terraform is only supported for Reserved Deployment Plan. Your Service Plan is: Basic_Plan for the instance 123"}, + {"Basic_Plan", "123", true, "[ERROR] Terraform is only supported for Reserved Deployment, Reserved Capacity, and Reserved Capacity Subscription Plans. Your Service Plan is: Basic_Plan for the instance 123"}, } for _, tt := range tests { @@ -145,7 +145,7 @@ func Test_checkSIPlan(t *testing.T) { name: "Cache Hit: Default Plan", cachePlan: "cached-default-plan", wantErr: true, - expectedErrorMessage: "[ERROR] Terraform is only supported for Reserved Deployment Plan. Your Service Plan is: cached-default-plan for the instance cached-default-plan", + expectedErrorMessage: "[ERROR] Terraform is only supported for Reserved Deployment, Reserved Capacity, and Reserved Capacity Subscription Plans. Your Service Plan is: cached-default-plan for the instance cached-default-plan", }, { name: "Reserved Deployment Plan Wildcard", @@ -161,7 +161,7 @@ func Test_checkSIPlan(t *testing.T) { name: "Default Plan", cachePlan: "default_plan_id", wantErr: true, - expectedErrorMessage: "[ERROR] Terraform is only supported for Reserved Deployment Plan. Your Service Plan is: default for the instance default_plan_id", + expectedErrorMessage: "[ERROR] Terraform is only supported for Reserved Deployment, Reserved Capacity, and Reserved Capacity Subscription Plans. Your Service Plan is: default for the instance default_plan_id", }, { name: "fetchServicePlanFunc Error: Invalid id", diff --git a/ibm/service/pag/resource_ibm_pag_instance.go b/ibm/service/pag/resource_ibm_pag_instance.go index cc03dccd88..98dfbf73b6 100644 --- a/ibm/service/pag/resource_ibm_pag_instance.go +++ b/ibm/service/pag/resource_ibm_pag_instance.go @@ -16,6 +16,13 @@ import ( func ResourceIBMPag() *schema.Resource { riSchema := resourcecontroller.ResourceIBMResourceInstance().Schema + riSchema["parameters_json"] = &schema.Schema{ + Type: schema.TypeString, + Description: "PAG parameters to pass in Json string format", + ForceNew: true, + Optional: true, + } + return &schema.Resource{ Create: resourcecontroller.ResourceIBMResourceInstanceCreate, Read: resourcecontroller.ResourceIBMResourceInstanceRead, diff --git a/ibm/service/pag/resource_ibm_pag_instance_test.go b/ibm/service/pag/resource_ibm_pag_instance_test.go index 4f801f6b80..22b8d96656 100644 --- a/ibm/service/pag/resource_ibm_pag_instance_test.go +++ b/ibm/service/pag/resource_ibm_pag_instance_test.go @@ -185,9 +185,9 @@ func testAccCheckIBMResourceInstanceBasic(cos_instance_name string, cos_bucket_n } ) timeouts { - create = "15m" - update = "15m" - delete = "15m" + create = "30m" + update = "30m" + delete = "30m" } } diff --git a/ibm/service/power/data_source_ibm_pi_datacenter.go b/ibm/service/power/data_source_ibm_pi_datacenter.go index 4bbb2f969e..d89c8a248f 100644 --- a/ibm/service/power/data_source_ibm_pi_datacenter.go +++ b/ibm/service/power/data_source_ibm_pi_datacenter.go @@ -21,6 +21,11 @@ func DataSourceIBMPIDatacenter() *schema.Resource { ReadContext: dataSourceIBMPIDatacenterRead, Schema: map[string]*schema.Schema{ // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", + Optional: true, + Type: schema.TypeString, + }, Arg_DatacenterZone: { Description: "Datacenter zone you want to retrieve.", Optional: true, @@ -180,7 +185,13 @@ func dataSourceIBMPIDatacenterRead(ctx context.Context, d *schema.ResourceData, if region, ok := d.GetOk(Arg_DatacenterZone); ok { datacenterZone = region.(string) } - client := instance.NewIBMPIDatacenterClient(ctx, sess, "") + + cloudInstanceID := "" + if cloudInstance, ok := d.GetOk(Arg_CloudInstanceID); ok { + cloudInstanceID = cloudInstance.(string) + } + client := instance.NewIBMPIDatacenterClient(ctx, sess, cloudInstanceID) + dcData, err := client.Get(datacenterZone) if err != nil { return diag.FromErr(err) diff --git a/ibm/service/power/data_source_ibm_pi_datacenter_test.go b/ibm/service/power/data_source_ibm_pi_datacenter_test.go index 0a7490c750..688fe0b0b4 100644 --- a/ibm/service/power/data_source_ibm_pi_datacenter_test.go +++ b/ibm/service/power/data_source_ibm_pi_datacenter_test.go @@ -4,6 +4,7 @@ package power_test import ( + "fmt" "testing" acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" @@ -25,9 +26,31 @@ func TestAccIBMPIDatacenterDataSourceBasic(t *testing.T) { }) } +func TestAccIBMPIDatacenterDataSourcePrivate(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIDatacenterDataSourcePrivateConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_datacenter.test", "id"), + ), + }, + }, + }) +} + func testAccCheckIBMPIDatacenterDataSourceConfig() string { return ` data "ibm_pi_datacenter" "test" { pi_datacenter_zone = "dal12" }` } + +func testAccCheckIBMPIDatacenterDataSourcePrivateConfig() string { + return fmt.Sprintf(` + data "ibm_pi_datacenter" "test" { + pi_cloud_instance_id = "%s" + }`, acc.Pi_cloud_instance_id) +} diff --git a/ibm/service/power/data_source_ibm_pi_datacenters.go b/ibm/service/power/data_source_ibm_pi_datacenters.go index f8d035a6be..531fa98d26 100644 --- a/ibm/service/power/data_source_ibm_pi_datacenters.go +++ b/ibm/service/power/data_source_ibm_pi_datacenters.go @@ -17,6 +17,13 @@ func DataSourceIBMPIDatacenters() *schema.Resource { return &schema.Resource{ ReadContext: dataSourceIBMPIDatacentersRead, Schema: map[string]*schema.Schema{ + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", + Optional: true, + Type: schema.TypeString, + }, + // Attributes Attr_Datacenters: { Type: schema.TypeList, @@ -173,7 +180,11 @@ func dataSourceIBMPIDatacentersRead(ctx context.Context, d *schema.ResourceData, if err != nil { return diag.FromErr(err) } - client := instance.NewIBMPIDatacenterClient(ctx, sess, "") + cloudInstanceID := "" + if cloudInstance, ok := d.GetOk(Arg_CloudInstanceID); ok { + cloudInstanceID = cloudInstance.(string) + } + client := instance.NewIBMPIDatacenterClient(ctx, sess, cloudInstanceID) datacentersData, err := client.GetAll() if err != nil { return diag.FromErr(err) diff --git a/ibm/service/power/data_source_ibm_pi_datacenters_test.go b/ibm/service/power/data_source_ibm_pi_datacenters_test.go index 83ba01a68e..4647dd5d91 100644 --- a/ibm/service/power/data_source_ibm_pi_datacenters_test.go +++ b/ibm/service/power/data_source_ibm_pi_datacenters_test.go @@ -4,6 +4,7 @@ package power_test import ( + "fmt" "testing" acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" @@ -25,6 +26,28 @@ func TestAccIBMPIDatacentersDataSourceBasic(t *testing.T) { }) } +func TestAccIBMPIDatacentersDataSourcePrivate(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPIDatacentersDataSourcePrivateConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_pi_datacenters.test", "id"), + ), + }, + }, + }) +} + func testAccCheckIBMPIDatacentersDataSourceConfig() string { return `data "ibm_pi_datacenters" "test" {}` } + +func testAccCheckIBMPIDatacentersDataSourcePrivateConfig() string { + return fmt.Sprintf(` + data "ibm_pi_datacenters" "test" { + pi_cloud_instance_id = "%s" + }`, acc.Pi_cloud_instance_id) +} diff --git a/ibm/service/power/data_source_ibm_pi_network.go b/ibm/service/power/data_source_ibm_pi_network.go index dec8dab0cc..bc699c4f07 100644 --- a/ibm/service/power/data_source_ibm_pi_network.go +++ b/ibm/service/power/data_source_ibm_pi_network.go @@ -37,7 +37,8 @@ func DataSourceIBMPINetwork() *schema.Resource { // Attributes Attr_AccessConfig: { Computed: true, - Description: "The network communication configuration option of the network (for satellite locations only).", + Deprecated: "This field is deprecated please use peer_id instead.", + Description: "The network communication configuration option of the network (for on prem locations only). Use `peer_id` instead.", Type: schema.TypeString, }, Attr_AvailableIPCount: { @@ -83,6 +84,25 @@ func DataSourceIBMPINetwork() *schema.Resource { Description: "The unique identifier or name of a network.", Type: schema.TypeString, }, + Attr_NetworkAddressTranslation: { + Computed: true, + Description: "Contains the network address translation details (for on prem locations only).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_SourceIP: { + Computed: true, + Description: "source IP address.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_PeerID: { + Computed: true, + Description: "Network peer ID (for on prem locations only).", + Type: schema.TypeString, + }, Attr_Type: { Computed: true, Description: "The type of network.", @@ -153,6 +173,13 @@ func dataSourceIBMPINetworkRead(ctx context.Context, d *schema.ResourceData, met if networkdata.Name != nil { d.Set(Attr_Name, networkdata.Name) } + networkAddressTranslation := []map[string]interface{}{} + if networkdata.NetworkAddressTranslation != nil { + natMap := networkAddressTranslationToMap(networkdata.NetworkAddressTranslation) + networkAddressTranslation = append(networkAddressTranslation, natMap) + } + d.Set(Attr_NetworkAddressTranslation, networkAddressTranslation) + d.Set(Attr_PeerID, networkdata.PeerID) if networkdata.Type != nil { d.Set(Attr_Type, networkdata.Type) } diff --git a/ibm/service/power/data_source_ibm_pi_network_peers.go b/ibm/service/power/data_source_ibm_pi_network_peers.go new file mode 100644 index 0000000000..3df2820dad --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_network_peers.go @@ -0,0 +1,109 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power + +import ( + "context" + + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + "github.com/IBM-Cloud/power-go-client/clients/instance" + "github.com/IBM-Cloud/power-go-client/power/models" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" +) + +func DataSourceIBMPINetworkPeers() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMPINetworkPeersRead, + + Schema: map[string]*schema.Schema{ + // Arguments + Arg_CloudInstanceID: { + Description: "The GUID of the service instance associated with an account.", + Required: true, + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, + }, + + // Attributes + Attr_NetworkPeers: { + Computed: true, + Description: "List of network peers.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_Description: { + Computed: true, + Description: "Description of the network peer.", + Type: schema.TypeString, + }, + Attr_ID: { + Computed: true, + Description: "ID of the network peer.", + Type: schema.TypeString, + }, + Attr_Name: { + Computed: true, + Description: "Name of the network peer.", + Type: schema.TypeString, + }, + Attr_Type: { + Computed: true, + Description: "Type of the network peer.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + }, + } +} + +func dataSourceIBMPINetworkPeersRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := meta.(conns.ClientSession).IBMPISession() + if err != nil { + return diag.FromErr(err) + } + cloudInstanceID := d.Get(Arg_CloudInstanceID).(string) + + networkC := instance.NewIBMPINetworkPeerClient(ctx, sess, cloudInstanceID) + networkdata, err := networkC.GetNetworkPeers() + if err != nil { + return diag.FromErr(err) + } + var clientgenU, _ = uuid.GenerateUUID() + d.SetId(clientgenU) + + networkPeers := []map[string]interface{}{} + if networkdata.NetworkPeers != nil { + for _, np := range networkdata.NetworkPeers { + npMap := dataSourceIBMPINetworkPeersNetworkPeerToMap(np) + + networkPeers = append(networkPeers, npMap) + } + } + d.Set(Attr_NetworkPeers, networkPeers) + + return nil +} + +func dataSourceIBMPINetworkPeersNetworkPeerToMap(np *models.NetworkPeer) map[string]interface{} { + npMap := make(map[string]interface{}) + if np.Description != nil { + npMap[Attr_Description] = np.Description + } + if np.ID != nil { + npMap[Attr_ID] = np.ID + } + if np.Name != nil { + npMap[Attr_Name] = np.Name + } + if np.Type != nil { + npMap[Attr_Type] = np.Type + } + return npMap +} diff --git a/ibm/service/power/data_source_ibm_pi_network_peers_test.go b/ibm/service/power/data_source_ibm_pi_network_peers_test.go new file mode 100644 index 0000000000..0493065877 --- /dev/null +++ b/ibm/service/power/data_source_ibm_pi_network_peers_test.go @@ -0,0 +1,37 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package power_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMPINetworkPeersDataSourceBasic(t *testing.T) { + networksResData := "data.ibm_pi_network_peers.network_peers" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPINetworkPeersDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(networksResData, "id"), + resource.TestCheckResourceAttrSet(networksResData, "network_peers.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMPINetworkPeersDataSourceConfigBasic() string { + return fmt.Sprintf(` + data "ibm_pi_network_peers" "network_peers" { + pi_cloud_instance_id = "%s" + }`, acc.Pi_cloud_instance_id) +} diff --git a/ibm/service/power/data_source_ibm_pi_networks.go b/ibm/service/power/data_source_ibm_pi_networks.go index db5c3ed5c2..5a4b48d40f 100644 --- a/ibm/service/power/data_source_ibm_pi_networks.go +++ b/ibm/service/power/data_source_ibm_pi_networks.go @@ -37,7 +37,8 @@ func DataSourceIBMPINetworks() *schema.Resource { Schema: map[string]*schema.Schema{ Attr_AccessConfig: { Computed: true, - Description: "The network communication configuration option of the network (for satellite locations only).", + Deprecated: "This field is deprecated please use peer_id instead.", + Description: "The network communication configuration option of the network (for on-prem locations only). Use `peer_id` instead.", Type: schema.TypeString, }, Attr_CRN: { @@ -70,6 +71,11 @@ func DataSourceIBMPINetworks() *schema.Resource { Description: "The unique identifier of a network.", Type: schema.TypeString, }, + Attr_PeerID: { + Computed: true, + Description: "Network Peer ID.", + Type: schema.TypeString, + }, Attr_Type: { Computed: true, Description: "The type of network.", @@ -126,6 +132,7 @@ func flattenNetworks(list []*models.NetworkReference, meta interface{}) []map[st Attr_MTU: i.Mtu, Attr_Name: *i.Name, Attr_NetworkID: *i.NetworkID, + Attr_PeerID: i.PeerID, Attr_Type: *i.Type, Attr_VLanID: *i.VlanID, } diff --git a/ibm/service/power/ibm_pi_constants.go b/ibm/service/power/ibm_pi_constants.go index f77e90fbf1..dc4bce648f 100644 --- a/ibm/service/power/ibm_pi_constants.go +++ b/ibm/service/power/ibm_pi_constants.go @@ -53,6 +53,7 @@ const ( Arg_NetworkID = "pi_network_id" Arg_NetworkInterfaceID = "pi_network_interface_id" Arg_NetworkName = "pi_network_name" + Arg_NetworkPeer = "pi_network_peer" Arg_NetworkSecurityGroupID = "pi_network_security_group_id" Arg_NetworkSecurityGroupMemberID = "pi_network_security_group_member_id" Arg_NetworkSecurityGroupRuleID = "pi_network_security_group_rule_id" @@ -280,9 +281,11 @@ const ( Attr_Name = "name" Attr_NetworkAddressGroupID = "network_address_group_id" Attr_NetworkAddressGroups = "network_address_groups" + Attr_NetworkAddressTranslation = "network_address_translation" Attr_NetworkID = "network_id" Attr_NetworkInterfaceID = "network_interface_id" Attr_NetworkName = "network_name" + Attr_NetworkPeers = "network_peers" Attr_NetworkPorts = "network_ports" Attr_Networks = "networks" Attr_NetworkSecurityGroupID = "network_security_group_id" @@ -292,6 +295,7 @@ const ( Attr_Onboardings = "onboardings" Attr_OperatingSystem = "operating_system" Attr_OSType = "os_type" + Attr_PeerID = "peer_id" Attr_PercentComplete = "percent_complete" Attr_PinPolicy = "pin_policy" Attr_PlacementGroupID = "placement_group_id" @@ -348,6 +352,7 @@ const ( Attr_SnapshotID = "snapshot_id" Attr_Source = "source" Attr_SourceChecksum = "source_checksum" + Attr_SourceIP = "source_ip" Attr_SourcePort = "source_port" Attr_SourceVolumeID = "source_volume_id" Attr_SourceVolumeName = "source_volume_name" @@ -474,6 +479,9 @@ const ( HostGroup = "hostGroup" ICMP = "icmp" IPV4_Address = "ipv4-address" + L2 = "L2" + L3BGP = "L3BGP" + L3Static = "L3Static" Master = "master" MaxVolumeSupport = "maxVolumeSupport" NAG = "network-address-group" diff --git a/ibm/service/power/resource_ibm_pi_network.go b/ibm/service/power/resource_ibm_pi_network.go index 3670aa3d10..392763bbf5 100644 --- a/ibm/service/power/resource_ibm_pi_network.go +++ b/ibm/service/power/resource_ibm_pi_network.go @@ -94,9 +94,47 @@ func ResourceIBMPINetwork() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, + Deprecated: "This field is deprecated please use pi_network_peer instead", ValidateFunc: validate.ValidateAllowedStringValues([]string{"internal-only", "outbound-only", "bidirectional-static-route", "bidirectional-bgp", "bidirectional-l2out"}), Description: "PI network communication configuration", }, + Arg_NetworkPeer: { + Description: "Network peer information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_ID: { + Description: "ID of the network peer.", + Required: true, + Type: schema.TypeString, + }, + Attr_NetworkAddressTranslation: { + Description: "Contains the network address translation Details.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_SourceIP: { + Description: "source IP address, required if network peer type is L3BGP or L3STATIC and if NAT is enabled.", + Required: true, + Type: schema.TypeString, + }, + }, + }, + MaxItems: 1, + Optional: true, + Type: schema.TypeList, + }, + Attr_Type: { + Description: "Type of the network peer.", + Optional: true, + Type: schema.TypeString, + ValidateFunc: validate.ValidateAllowedStringValues([]string{L2, L3BGP, L3Static}), + }, + }, + }, + ForceNew: true, + MaxItems: 1, + Optional: true, + Type: schema.TypeList, + }, helpers.PICloudInstanceId: { Type: schema.TypeString, Required: true, @@ -141,6 +179,25 @@ func ResourceIBMPINetwork() *schema.Resource { Computed: true, Description: "PI network ID", }, + Attr_NetworkAddressTranslation: { + Computed: true, + Description: "Contains the Network Address Translation Details (for on-prem locations only).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + Attr_SourceIP: { + Computed: true, + Description: "source IP address, required if network peer type is L3BGP or L3STATIC and if NAT is enabled.", + Type: schema.TypeString, + }, + }, + }, + Type: schema.TypeList, + }, + Attr_PeerID: { + Computed: true, + Description: "Network Peer ID (for on-prem locations only).", + Type: schema.TypeString, + }, "vlan_id": { Type: schema.TypeFloat, Computed: true, @@ -158,7 +215,6 @@ func resourceIBMPINetworkCreate(ctx context.Context, d *schema.ResourceData, met cloudInstanceID := d.Get(helpers.PICloudInstanceId).(string) networkname := d.Get(helpers.PINetworkName).(string) networktype := d.Get(helpers.PINetworkType).(string) - client := instance.NewIBMPINetworkClient(ctx, sess, cloudInstanceID) var body = &models.NetworkCreate{ Type: &networktype, @@ -183,6 +239,10 @@ func resourceIBMPINetworkCreate(ctx context.Context, d *schema.ResourceData, met if v, ok := d.GetOk(helpers.PINetworkAccessConfig); ok { body.AccessConfig = models.AccessConfig(v.(string)) } + if _, ok := d.GetOk(Arg_NetworkPeer); ok { + peerModel := networkMapToNetworkCreatePeer(d.Get(Arg_NetworkPeer + ".0").(map[string]interface{})) + body.Peer = peerModel + } if networktype == DHCPVlan || networktype == Vlan { var networkcidr string @@ -212,17 +272,20 @@ func resourceIBMPINetworkCreate(ctx context.Context, d *schema.ResourceData, met body.Gateway = gateway body.Cidr = networkcidr } - wsclient := instance.NewIBMPIWorkspacesClient(ctx, sess, cloudInstanceID) - wsData, err := wsclient.Get(cloudInstanceID) - if err != nil { - return diag.FromErr(err) - } - if wsData.Capabilities[PER] { - _, err = waitForPERWorkspaceActive(ctx, wsclient, cloudInstanceID, d.Timeout(schema.TimeoutRead)) + if !sess.IsOnPrem() { + wsclient := instance.NewIBMPIWorkspacesClient(ctx, sess, cloudInstanceID) + wsData, err := wsclient.Get(cloudInstanceID) if err != nil { return diag.FromErr(err) } + if wsData.Capabilities[PER] { + _, err = waitForPERWorkspaceActive(ctx, wsclient, cloudInstanceID, d.Timeout(schema.TimeoutRead)) + if err != nil { + return diag.FromErr(err) + } + } } + networkResponse, err := client.Create(body) if err != nil { return diag.FromErr(err) @@ -284,6 +347,13 @@ func resourceIBMPINetworkRead(ctx context.Context, d *schema.ResourceData, meta d.Set(helpers.PINetworkMtu, networkdata.Mtu) d.Set(helpers.PINetworkAccessConfig, networkdata.AccessConfig) d.Set(helpers.PINetworkGateway, networkdata.Gateway) + d.Set(Attr_PeerID, networkdata.PeerID) + networkAddressTranslation := []map[string]interface{}{} + if networkdata.NetworkAddressTranslation != nil { + natMap := networkAddressTranslationToMap(networkdata.NetworkAddressTranslation) + networkAddressTranslation = append(networkAddressTranslation, natMap) + } + d.Set(Attr_NetworkAddressTranslation, networkAddressTranslation) ipRangesMap := []map[string]interface{}{} if networkdata.IPAddressRanges != nil { for _, n := range networkdata.IPAddressRanges { @@ -529,3 +599,33 @@ func isPERWorkspaceRefreshFunc(client *instance.IBMPIWorkspacesClient, id string return ws, State_Configuring, nil } } +func networkMapToNetworkCreatePeer(networkCreatePeerMap map[string]interface{}) *models.NetworkCreatePeer { + ncp := &models.NetworkCreatePeer{} + if networkCreatePeerMap[Attr_ID].(string) != "" { + id := networkCreatePeerMap[Attr_ID].(string) + ncp.ID = &id + } + if networkCreatePeerMap[Attr_NetworkAddressTranslation] != nil && len(networkCreatePeerMap[Attr_NetworkAddressTranslation].([]interface{})) > 0 { + networkAddressTranslationModel := natMapToNetworkAddressTranslation(networkCreatePeerMap[Attr_NetworkAddressTranslation].([]interface{})[0].(map[string]interface{})) + ncp.NetworkAddressTranslation = networkAddressTranslationModel + } + if networkCreatePeerMap[Attr_Type].(string) != "" { + ncp.Type = models.NetworkPeerType(networkCreatePeerMap[Attr_Type].(string)) + } + return ncp +} +func natMapToNetworkAddressTranslation(networkAddressTranslationMap map[string]interface{}) *models.NetworkAddressTranslation { + nat := &models.NetworkAddressTranslation{} + if networkAddressTranslationMap[Attr_SourceIP].(string) != "" { + nat.SourceIP = networkAddressTranslationMap[Attr_SourceIP].(string) + } + return nat +} + +func networkAddressTranslationToMap(nat *models.NetworkAddressTranslation) map[string]interface{} { + natMap := make(map[string]interface{}) + if nat.SourceIP != "" { + natMap[Attr_SourceIP] = nat.SourceIP + } + return natMap +} diff --git a/ibm/service/power/resource_ibm_pi_network_test.go b/ibm/service/power/resource_ibm_pi_network_test.go index b62dac6513..a3cd335ac0 100644 --- a/ibm/service/power/resource_ibm_pi_network_test.go +++ b/ibm/service/power/resource_ibm_pi_network_test.go @@ -188,7 +188,26 @@ func TestAccIBMPINetworkUserTags(t *testing.T) { }, }) } - +func TestAccIBMPINetworkPeerOnPrem(t *testing.T) { + name := fmt.Sprintf("tf-pi-network-%d", acctest.RandIntRange(10, 100)) + networkRes := "ibm_pi_network.power_network_peer" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPINetworkDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPINetworkPeerOnPrem(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMPINetworkExists(networkRes), + resource.TestCheckResourceAttr(networkRes, "pi_network_name", name), + resource.TestCheckResourceAttrSet(networkRes, "id"), + resource.TestCheckResourceAttrSet(networkRes, "peer_id"), + ), + }, + }, + }) +} func testAccCheckIBMPINetworkDestroy(s *terraform.State) error { sess, err := acc.TestAccProvider.Meta().(conns.ClientSession).IBMPISession() if err != nil { @@ -338,3 +357,19 @@ func testAccCheckIBMPINetworkUserTagsConfig(name string, userTagsString string) } `, acc.Pi_cloud_instance_id, name, userTagsString) } + +func testAccCheckIBMPINetworkPeerOnPrem(name string) string { + return fmt.Sprintf(` + resource "ibm_pi_network" "power_network_peer" { + pi_cloud_instance_id = "%s" + pi_network_name = "%s" + pi_network_type = "vlan" + pi_cidr = "192.168.17.0/24" + + pi_network_peer { + id = "2" + type = "L2" + } + } + `, acc.Pi_cloud_instance_id, name) +} diff --git a/ibm/service/scc/resource_ibm_scc_instance_settings.go b/ibm/service/scc/resource_ibm_scc_instance_settings.go index f501c00919..e96e7c97d1 100644 --- a/ibm/service/scc/resource_ibm_scc_instance_settings.go +++ b/ibm/service/scc/resource_ibm_scc_instance_settings.go @@ -34,8 +34,20 @@ func ResourceIbmSccInstanceSettings() *schema.Resource { "instance_crn": &schema.Schema{ Type: schema.TypeString, Optional: true, + Computed: true, Description: "The Event Notifications instance CRN.", }, + "source_description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The description of the source in Event Notifications connected Security and Compliance Center", + }, + "source_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The name of the Event Notifications source connected Security and Compliance Center instance CRN.", + }, "updated_on": &schema.Schema{ Type: schema.TypeString, Computed: true, @@ -123,11 +135,8 @@ func resourceIbmSccInstanceSettingsCreate(context context.Context, d *schema.Res return diag.FromErr(err) } eventNotificationsModel = eventNotificationsData - eventNotificationsModel.SourceName = core.StringPtr("compliance") - eventNotificationsModel.SourceDescription = core.StringPtr("This source is used for integration with IBM Cloud Security and Compliance Center.") } else { eventNotificationsModel = &securityandcompliancecenterapiv3.EventNotifications{} - eventNotificationsModel.InstanceCrn = core.StringPtr("") } updateSettingsOptions.SetEventNotifications(eventNotificationsModel) @@ -139,8 +148,7 @@ func resourceIbmSccInstanceSettingsCreate(context context.Context, d *schema.Res } objectStorageModel = objectStorageData } else { - objectStorageModel := &securityandcompliancecenterapiv3.ObjectStorage{} - objectStorageModel.InstanceCrn = core.StringPtr("") + objectStorageModel = &securityandcompliancecenterapiv3.ObjectStorage{} } updateSettingsOptions.SetObjectStorage(objectStorageModel) @@ -183,6 +191,13 @@ func resourceIbmSccInstanceSettingsRead(context context.Context, d *schema.Resou if err != nil { return diag.FromErr(err) } + if _, ok := eventNotificationsMap["source_name"]; !ok { + eventNotificationsData, enErr := resourceIbmSccInstanceSettingsMapToEventNotifications(d.Get("event_notifications.0").(map[string]interface{})) + if enErr == nil && core.StringNilMapper(eventNotificationsData.SourceName) != "" { + eventNotificationsMap["source_name"] = eventNotificationsData.SourceName + log.Print("[WARN] event_notifications.source_name grabbed from preexisting state\n") + } + } if err = d.Set("event_notifications", []map[string]interface{}{eventNotificationsMap}); err != nil { return diag.FromErr(flex.FmtErrorf("Error setting event_notifications: %s", err)) } @@ -217,10 +232,6 @@ func resourceIbmSccInstanceSettingsUpdate(context context.Context, d *schema.Res if err != nil { return diag.FromErr(err) } - if eventNotifications.InstanceCrn != nil && *eventNotifications.InstanceCrn != "" { - eventNotifications.SourceName = core.StringPtr("compliance") - eventNotifications.SourceDescription = core.StringPtr("This source is used for integration with IBM Cloud Security and Compliance Center.") - } updateSettingsOptions.SetEventNotifications(eventNotifications) hasChange = true } @@ -266,6 +277,15 @@ func resourceIbmSccInstanceSettingsMapToEventNotifications(modelMap map[string]i if modelMap["source_id"] != nil && modelMap["source_id"].(string) != "" { model.SourceID = core.StringPtr(modelMap["source_id"].(string)) } + if modelMap["source_name"] != nil && modelMap["source_name"].(string) != "" { + model.SourceName = core.StringPtr(modelMap["source_name"].(string)) + } + if modelMap["source_description"] != nil && modelMap["source_description"].(string) != "" { + model.SourceDescription = core.StringPtr(modelMap["source_description"].(string)) + } + if core.StringNilMapper(model.InstanceCrn) != "" && core.StringNilMapper(model.SourceName) == "" { + return model, errors.New("event_notifications.source_name needs to be defined along with event_notifications.instance_crn") + } return model, nil } diff --git a/ibm/service/scc/resource_ibm_scc_instance_settings_test.go b/ibm/service/scc/resource_ibm_scc_instance_settings_test.go index c74b3947d8..d8914a4d63 100644 --- a/ibm/service/scc/resource_ibm_scc_instance_settings_test.go +++ b/ibm/service/scc/resource_ibm_scc_instance_settings_test.go @@ -24,7 +24,7 @@ func TestAccIbmSccInstanceSettingsBasic(t *testing.T) { Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIbmSccInstanceSettingsDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmSccInstanceSettingsConfigBasic(acc.SccInstanceID), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIbmSccInstanceSettingsExists("ibm_scc_instance_settings.scc_instance_settings_instance", conf), @@ -42,19 +42,19 @@ func TestAccIbmSccInstanceSettingsAllArgs(t *testing.T) { Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIbmSccInstanceSettingsDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckIbmSccInstanceSettingsConfigBasic(acc.SccInstanceID), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIbmSccInstanceSettingsExists("ibm_scc_instance_settings.scc_instance_settings_instance", conf), ), }, - resource.TestStep{ + { Config: testAccCheckIbmSccInstanceSettingsConfig(acc.SccInstanceID, acc.SccEventNotificationsCRN, acc.SccObjectStorageCRN, acc.SccObjectStorageBucket), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIbmSccInstanceSettingsExists("ibm_scc_instance_settings.scc_instance_settings_instance", conf), ), }, - resource.TestStep{ + { ResourceName: "ibm_scc_instance_settings.scc_instance_settings_instance", ImportState: true, ImportStateVerify: true, @@ -66,7 +66,7 @@ func TestAccIbmSccInstanceSettingsAllArgs(t *testing.T) { func testAccCheckIbmSccInstanceSettingsConfigBasic(instanceID string) string { return fmt.Sprintf(` resource "ibm_scc_instance_settings" "scc_instance_settings_instance" { - instance_id = "%s" + instance_id = "%s" event_notifications { } object_storage { } } @@ -79,6 +79,7 @@ func testAccCheckIbmSccInstanceSettingsConfig(instanceID, enInstanceCRN, objStor instance_id = "%s" event_notifications { instance_crn = "%s" + source_name = "scc compliance" } object_storage { instance_crn = "%s" @@ -89,7 +90,6 @@ func testAccCheckIbmSccInstanceSettingsConfig(instanceID, enInstanceCRN, objStor } func testAccCheckIbmSccInstanceSettingsExists(n string, obj securityandcompliancecenterapiv3.Settings) resource.TestCheckFunc { - return func(s *terraform.State) error { _, ok := s.RootModule().Resources[n] if !ok { diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server.go index 529ff295df..0481d4e619 100644 --- a/ibm/service/vpc/data_source_ibm_is_bare_metal_server.go +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server.go @@ -756,6 +756,144 @@ func DataSourceIBMIsBareMetalServer() *schema.Resource { Set: flex.ResourceIBMVPCHash, Description: "List of access tags", }, + "health_reasons": { + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current health_state (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the reason for this health state.", + }, + "message": { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this health state.", + }, + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this health state.", + }, + }, + }, + }, + "health_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The health of this resource", + }, + isReservation: { + Type: schema.TypeList, + Computed: true, + Description: "The reservation used by this bare metal server", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isReservationId: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reservation.", + }, + isReservationCrn: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this reservation.", + }, + isReservationName: { + Type: schema.TypeString, + Computed: true, + Description: "The name for this reservation. The name is unique across all reservations in the region.", + }, + isReservationHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reservation.", + }, + isReservationResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + isReservationDeleted: &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{ + isReservationDeletedMoreInfo: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + }, + }, + }, + isReservationAffinity: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isReservationAffinityPolicyResp: { + Type: schema.TypeString, + Computed: true, + Description: "The reservation affinity policy to use for this bare metal server.", + }, + isReservationAffinityPool: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The pool of reservations available for use by this bare metal server.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isReservationId: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reservation.", + }, + isReservationCrn: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this reservation.", + }, + isReservationName: { + Type: schema.TypeString, + Computed: true, + Description: "The name for this reservation. The name is unique across all reservations in the region.", + }, + isReservationHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reservation.", + }, + isReservationResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + isReservationDeleted: &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{ + isReservationDeletedMoreInfo: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, }, } } @@ -1161,6 +1299,71 @@ func dataSourceIBMISBareMetalServerRead(context context.Context, d *schema.Resou } d.Set(isBareMetalServerAccessTags, accesstags) + if bms.HealthReasons != nil { + healthReasonsList := make([]map[string]interface{}, 0) + for _, sr := range bms.HealthReasons { + currentSR := map[string]interface{}{} + if sr.Code != nil && sr.Message != nil { + currentSR["code"] = *sr.Code + currentSR["message"] = *sr.Message + if sr.MoreInfo != nil { + currentSR["more_info"] = *sr.Message + } + healthReasonsList = append(healthReasonsList, currentSR) + } + } + d.Set("health_reasons", healthReasonsList) + } + if err = d.Set("health_state", bms.HealthState); err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error setting health_state: %s", err)) + } + if bms.ReservationAffinity != nil { + reservationAffinity := []map[string]interface{}{} + reservationAffinityMap := map[string]interface{}{} + + reservationAffinityMap[isReservationAffinityPolicyResp] = bms.ReservationAffinity.Policy + if bms.ReservationAffinity.Pool != nil { + poolList := make([]map[string]interface{}, 0) + for _, pool := range bms.ReservationAffinity.Pool { + res := map[string]interface{}{} + + res[isReservationId] = *pool.ID + res[isReservationHref] = *pool.Href + res[isReservationName] = *pool.Name + res[isReservationCrn] = *pool.CRN + res[isReservationResourceType] = *pool.ResourceType + if pool.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceReservationDeletedToMap(*pool.Deleted) + deletedList = append(deletedList, deletedMap) + res[isReservationDeleted] = deletedList + } + poolList = append(poolList, res) + } + reservationAffinityMap[isReservationAffinityPool] = poolList + } + reservationAffinity = append(reservationAffinity, reservationAffinityMap) + d.Set(isReservationAffinity, reservationAffinity) + } + if bms.Reservation != nil { + resList := make([]map[string]interface{}, 0) + res := map[string]interface{}{} + + res[isReservationId] = *bms.Reservation.ID + res[isReservationHref] = *bms.Reservation.Href + res[isReservationName] = *bms.Reservation.Name + res[isReservationCrn] = *bms.Reservation.CRN + res[isReservationResourceType] = *bms.Reservation.ResourceType + if bms.Reservation.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceReservationDeletedToMap(*bms.Reservation.Deleted) + deletedList = append(deletedList, deletedMap) + res[isReservationDeleted] = deletedList + } + resList = append(resList, res) + d.Set(isReservation, resList) + } + return nil } diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profile.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profile.go index 6247adeb2d..82a7bbb039 100644 --- a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profile.go +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profile.go @@ -408,6 +408,28 @@ func DataSourceIBMIsBareMetalServerProfile() *schema.Resource { }, }, }, + "reservation_terms": { + Type: schema.TypeList, + Computed: true, + Description: "The type for this profile field", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "values": { + Type: schema.TypeList, + Computed: true, + Description: "The supported committed use terms for a reservation using this profile", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, }, } } @@ -611,10 +633,37 @@ func dataSourceIBMISBMSProfileRead(context context.Context, d *schema.ResourceDa return diag.FromErr(fmt.Errorf("Error setting network_attachment_count %s", err)) } } + if bmsProfile.ReservationTerms != nil { + err = d.Set("reservation_terms", dataSourceBaremetalServerProfileFlattenReservationTerms(*bmsProfile.ReservationTerms)) + if err != nil { + return diag.FromErr(fmt.Errorf("Error setting reservation_terms %s", err)) + } + } return nil } +func dataSourceBaremetalServerProfileFlattenReservationTerms(result vpcv1.BareMetalServerProfileReservationTerms) (finalList []map[string]interface{}) { + finalList = []map[string]interface{}{} + finalMap := dataSourceBaremetalServerProfileReservationTermsToMap(result) + finalList = append(finalList, finalMap) + + return finalList +} + +func dataSourceBaremetalServerProfileReservationTermsToMap(resTermItem vpcv1.BareMetalServerProfileReservationTerms) map[string]interface{} { + resTermMap := map[string]interface{}{} + + if resTermItem.Type != nil { + resTermMap["type"] = resTermItem.Type + } + if resTermItem.Values != nil { + resTermMap["values"] = resTermItem.Values + } + + return resTermMap +} + func dataSourceIBMIsBareMetalServerProfileBareMetalServerProfileConsoleTypesToMap(model *vpcv1.BareMetalServerProfileConsoleTypes) (map[string]interface{}, error) { modelMap := make(map[string]interface{}) modelMap["type"] = model.Type diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profile_test.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profile_test.go index d3265274ca..70f3030a3c 100644 --- a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profile_test.go +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_profile_test.go @@ -42,6 +42,9 @@ func TestAccIBMISBMSProfileDataSource_basic(t *testing.T) { resource.TestCheckResourceAttrSet(resName, "os_architecture.#"), resource.TestCheckResourceAttrSet(resName, "resource_type"), resource.TestCheckResourceAttrSet(resName, "supported_trusted_platform_module_modes.#"), + resource.TestCheckResourceAttrSet(resName, "reservation_terms.#"), + resource.TestCheckResourceAttrSet(resName, "reservation_terms.0.type"), + resource.TestCheckResourceAttrSet(resName, "reservation_terms.0.values"), ), }, }, diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_servers.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_servers.go index f639006c02..cbb4aa7753 100644 --- a/ibm/service/vpc/data_source_ibm_is_bare_metal_servers.go +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_servers.go @@ -799,6 +799,144 @@ func DataSourceIBMIsBareMetalServers() *schema.Resource { Set: flex.ResourceIBMVPCHash, Description: "List of access tags", }, + "health_reasons": { + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current health_state (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the reason for this health state.", + }, + "message": { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this health state.", + }, + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this health state.", + }, + }, + }, + }, + "health_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The health of this resource", + }, + isReservation: { + Type: schema.TypeList, + Computed: true, + Description: "The reservation used by this bare metal server", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isReservationId: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reservation.", + }, + isReservationCrn: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this reservation.", + }, + isReservationName: { + Type: schema.TypeString, + Computed: true, + Description: "The name for this reservation. The name is unique across all reservations in the region.", + }, + isReservationHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reservation.", + }, + isReservationResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + isReservationDeleted: &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{ + isReservationDeletedMoreInfo: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + }, + }, + }, + isReservationAffinity: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isReservationAffinityPolicyResp: { + Type: schema.TypeString, + Computed: true, + Description: "The reservation affinity policy to use for this bare metal server.", + }, + isReservationAffinityPool: &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The pool of reservations available for use by this bare metal server.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isReservationId: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reservation.", + }, + isReservationCrn: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this reservation.", + }, + isReservationName: { + Type: schema.TypeString, + Computed: true, + Description: "The name for this reservation. The name is unique across all reservations in the region.", + }, + isReservationHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reservation.", + }, + isReservationResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + isReservationDeleted: &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{ + isReservationDeletedMoreInfo: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, }, }, }, @@ -1180,6 +1318,62 @@ func dataSourceIBMISBareMetalServersRead(context context.Context, d *schema.Reso if bms.ResourceGroup != nil { l[isBareMetalServerResourceGroup] = *bms.ResourceGroup.ID } + if bms.HealthReasons != nil { + healthReasonsList := []map[string]interface{}{} + for _, healthReasonsItem := range bms.HealthReasons { + healthReasonsList = append(healthReasonsList, dataSourceBaremetalServersCollectionHealthReasonsToMap(healthReasonsItem)) + } + l["health_reasons"] = healthReasonsList + } + if bms.HealthState != nil { + l["health_state"] = bms.HealthState + } + if bms.ReservationAffinity != nil { + reservationAffinity := []map[string]interface{}{} + reservationAffinityMap := map[string]interface{}{} + + reservationAffinityMap[isReservationAffinityPolicyResp] = bms.ReservationAffinity.Policy + if bms.ReservationAffinity.Pool != nil { + poolList := make([]map[string]interface{}, 0) + for _, pool := range bms.ReservationAffinity.Pool { + res := map[string]interface{}{} + + res[isReservationId] = *pool.ID + res[isReservationHref] = *pool.Href + res[isReservationName] = *pool.Name + res[isReservationCrn] = *pool.CRN + res[isReservationResourceType] = *pool.ResourceType + if pool.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceReservationDeletedToMap(*pool.Deleted) + deletedList = append(deletedList, deletedMap) + res[isReservationDeleted] = deletedList + } + poolList = append(poolList, res) + } + reservationAffinityMap[isReservationAffinityPool] = poolList + } + reservationAffinity = append(reservationAffinity, reservationAffinityMap) + l[isReservationAffinity] = reservationAffinity + } + if bms.Reservation != nil { + resList := make([]map[string]interface{}, 0) + res := map[string]interface{}{} + + res[isReservationId] = *bms.Reservation.ID + res[isReservationHref] = *bms.Reservation.Href + res[isReservationName] = *bms.Reservation.Name + res[isReservationCrn] = *bms.Reservation.CRN + res[isReservationResourceType] = *bms.Reservation.ResourceType + if bms.Reservation.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceReservationDeletedToMap(*bms.Reservation.Deleted) + deletedList = append(deletedList, deletedMap) + res[isReservationDeleted] = deletedList + } + resList = append(resList, res) + l[isReservation] = resList + } serversInfo = append(serversInfo, l) } d.SetId(dataSourceIBMISBareMetalServersID(d)) @@ -1187,6 +1381,22 @@ func dataSourceIBMISBareMetalServersRead(context context.Context, d *schema.Reso return nil } +func dataSourceBaremetalServersCollectionHealthReasonsToMap(statusReasonsItem vpcv1.BareMetalServerHealthReason) (healthReasonsMap map[string]interface{}) { + healthReasonsMap = map[string]interface{}{} + + if statusReasonsItem.Code != nil { + healthReasonsMap["code"] = statusReasonsItem.Code + } + if statusReasonsItem.Message != nil { + healthReasonsMap["message"] = statusReasonsItem.Message + } + if statusReasonsItem.MoreInfo != nil { + healthReasonsMap["more_info"] = statusReasonsItem.MoreInfo + } + + return healthReasonsMap +} + // dataSourceIBMISBareMetalServersID returns a reasonable ID for a Bare Metal Servers list. func dataSourceIBMISBareMetalServersID(d *schema.ResourceData) string { return time.Now().UTC().String() diff --git a/ibm/service/vpc/data_source_ibm_is_cluster_network.go b/ibm/service/vpc/data_source_ibm_is_cluster_network.go new file mode 100644 index 0000000000..439ab3f664 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_cluster_network.go @@ -0,0 +1,394 @@ +// Copyright IBM Corp. 2024 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/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsClusterNetwork() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsClusterNetworkRead, + + Schema: map[string]*schema.Schema{ + "cluster_network_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The cluster network identifier.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the cluster network was created.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this cluster network.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network.", + }, + "lifecycle_reasons": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current `lifecycle_state` (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the cluster network.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network. The name must not be used by another cluster network in the region.", + }, + "profile": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The profile for this cluster network.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network profile.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this cluster network profile.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "resource_group": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The resource group for this cluster network.", + 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.", + }, + "subnet_prefixes": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The IP address ranges available for subnets for this cluster network.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allocation_policy": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The allocation policy for this subnet prefix:- `auto`: Subnets created by total count in this cluster network can use this prefix.", + }, + "cidr": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CIDR block for this prefix.", + }, + }, + }, + }, + "vpc": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The VPC this cluster network resides in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this VPC.", + }, + "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 VPC.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this VPC. The name is unique across all VPCs in the region.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "zone": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The zone this cluster network resides in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this zone.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this zone.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsClusterNetworkRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + getClusterNetworkOptions := &vpcv1.GetClusterNetworkOptions{} + + getClusterNetworkOptions.SetID(d.Get("cluster_network_id").(string)) + + clusterNetwork, _, err := vpcClient.GetClusterNetworkWithContext(context, getClusterNetworkOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetClusterNetworkWithContext failed: %s", err.Error()), "(Data) ibm_is_cluster_network", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(*getClusterNetworkOptions.ID) + + if err = d.Set("created_at", flex.DateTimeToString(clusterNetwork.CreatedAt)); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting created_at: %s", err), "(Data) ibm_is_cluster_network", "read", "set-created_at").GetDiag() + } + + if err = d.Set("crn", clusterNetwork.CRN); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting crn: %s", err), "(Data) ibm_is_cluster_network", "read", "set-crn").GetDiag() + } + + if err = d.Set("href", clusterNetwork.Href); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting href: %s", err), "(Data) ibm_is_cluster_network", "read", "set-href").GetDiag() + } + + lifecycleReasons := []map[string]interface{}{} + for _, lifecycleReasonsItem := range clusterNetwork.LifecycleReasons { + lifecycleReasonsItemMap, err := DataSourceIBMIsClusterNetworkClusterNetworkLifecycleReasonToMap(&lifecycleReasonsItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network", "read", "lifecycle_reasons-to-map").GetDiag() + } + lifecycleReasons = append(lifecycleReasons, lifecycleReasonsItemMap) + } + if err = d.Set("lifecycle_reasons", lifecycleReasons); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting lifecycle_reasons: %s", err), "(Data) ibm_is_cluster_network", "read", "set-lifecycle_reasons").GetDiag() + } + + if err = d.Set("lifecycle_state", clusterNetwork.LifecycleState); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting lifecycle_state: %s", err), "(Data) ibm_is_cluster_network", "read", "set-lifecycle_state").GetDiag() + } + + if err = d.Set("name", clusterNetwork.Name); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting name: %s", err), "(Data) ibm_is_cluster_network", "read", "set-name").GetDiag() + } + + profile := []map[string]interface{}{} + profileMap, err := DataSourceIBMIsClusterNetworkClusterNetworkProfileReferenceToMap(clusterNetwork.Profile) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network", "read", "profile-to-map").GetDiag() + } + profile = append(profile, profileMap) + if err = d.Set("profile", profile); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting profile: %s", err), "(Data) ibm_is_cluster_network", "read", "set-profile").GetDiag() + } + + resourceGroup := []map[string]interface{}{} + resourceGroupMap, err := DataSourceIBMIsClusterNetworkResourceGroupReferenceToMap(clusterNetwork.ResourceGroup) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network", "read", "resource_group-to-map").GetDiag() + } + resourceGroup = append(resourceGroup, resourceGroupMap) + if err = d.Set("resource_group", resourceGroup); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting resource_group: %s", err), "(Data) ibm_is_cluster_network", "read", "set-resource_group").GetDiag() + } + + if err = d.Set("resource_type", clusterNetwork.ResourceType); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting resource_type: %s", err), "(Data) ibm_is_cluster_network", "read", "set-resource_type").GetDiag() + } + + subnetPrefixes := []map[string]interface{}{} + for _, subnetPrefixesItem := range clusterNetwork.SubnetPrefixes { + subnetPrefixesItemMap, err := DataSourceIBMIsClusterNetworkClusterNetworkSubnetPrefixToMap(&subnetPrefixesItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network", "read", "subnet_prefixes-to-map").GetDiag() + } + subnetPrefixes = append(subnetPrefixes, subnetPrefixesItemMap) + } + if err = d.Set("subnet_prefixes", subnetPrefixes); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting subnet_prefixes: %s", err), "(Data) ibm_is_cluster_network", "read", "set-subnet_prefixes").GetDiag() + } + + vpc := []map[string]interface{}{} + vpcMap, err := DataSourceIBMIsClusterNetworkVPCReferenceToMap(clusterNetwork.VPC) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network", "read", "vpc-to-map").GetDiag() + } + vpc = append(vpc, vpcMap) + if err = d.Set("vpc", vpc); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting vpc: %s", err), "(Data) ibm_is_cluster_network", "read", "set-vpc").GetDiag() + } + + zone := []map[string]interface{}{} + zoneMap, err := DataSourceIBMIsClusterNetworkZoneReferenceToMap(clusterNetwork.Zone) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network", "read", "zone-to-map").GetDiag() + } + zone = append(zone, zoneMap) + if err = d.Set("zone", zone); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting zone: %s", err), "(Data) ibm_is_cluster_network", "read", "set-zone").GetDiag() + } + + return nil +} + +func DataSourceIBMIsClusterNetworkClusterNetworkLifecycleReasonToMap(model *vpcv1.ClusterNetworkLifecycleReason) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["code"] = *model.Code + modelMap["message"] = *model.Message + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkClusterNetworkProfileReferenceToMap(model *vpcv1.ClusterNetworkProfileReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["name"] = *model.Name + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkResourceGroupReferenceToMap(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 DataSourceIBMIsClusterNetworkClusterNetworkSubnetPrefixToMap(model *vpcv1.ClusterNetworkSubnetPrefix) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["allocation_policy"] = *model.AllocationPolicy + modelMap["cidr"] = *model.CIDR + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkVPCReferenceToMap(model *vpcv1.VPCReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = *model.CRN + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsClusterNetworkDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkDeletedToMap(model *vpcv1.Deleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = *model.MoreInfo + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkZoneReferenceToMap(model *vpcv1.ZoneReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["name"] = *model.Name + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_cluster_network_interface.go b/ibm/service/vpc/data_source_ibm_is_cluster_network_interface.go new file mode 100644 index 0000000000..95cfa51fcc --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_cluster_network_interface.go @@ -0,0 +1,538 @@ +// Copyright IBM Corp. 2024 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/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsClusterNetworkInterface() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsClusterNetworkInterfaceRead, + + Schema: map[string]*schema.Schema{ + "cluster_network_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The cluster network identifier.", + }, + "cluster_network_interface_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The cluster network interface identifier.", + }, + "allow_ip_spoofing": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether source IP spoofing is allowed on this cluster network interface. If `false`, source IP spoofing is prevented on this cluster network interface. If `true`, source IP spoofing is allowed on this cluster network interface.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this cluster network interface will be automatically deleted when `target` is deleted.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the cluster network interface was created.", + }, + "enable_infrastructure_nat": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "If `true`:- The VPC infrastructure performs any needed NAT operations.- `floating_ips` must not have more than one floating IP.If `false`:- Packets are passed unchanged to/from the virtual network interface, allowing the workload to perform any needed NAT operations.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network interface.", + }, + "lifecycle_reasons": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current `lifecycle_state` (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the cluster network interface.", + }, + "mac_address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The MAC address of the cluster network interface. May be absent if`lifecycle_state` is `pending`.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network interface. The name is unique across all interfaces in the cluster network.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The cluster network subnet reserved IP for this cluster network interface.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address is pending allocation, the value will be `0.0.0.0`.This property may [expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) to support IPv6 addresses in the future.", + }, + "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 cluster network subnet reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network subnet reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network subnet reserved IP. The name is unique across all reserved IPs in a cluster network subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + // "protocol_state_filtering_mode": &schema.Schema{ + // Type: schema.TypeString, + // Computed: true, + // Description: "The protocol state filtering mode used for this cluster network interface.Protocol state filtering monitors each network connection flowing over this cluster network interface, and drops any packets that are invalid based on the current connection state and protocol. See [Protocol state filtering mode](https://cloud.ibm.com/docs/vpc?topic=vpc-vni-about#protocol-state-filtering) for more information.The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + // }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "subnet": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + 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 cluster network subnet.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network subnet. The name is unique across all cluster network subnets in the cluster network.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "target": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The target of this cluster network interface.If absent, this cluster network interface is not attached to a target.The resources supported by this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this instance cluster network attachment.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance cluster network attachment.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this instance cluster network attachment. The name is unique across all network attachments for the instance.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "vpc": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The VPC this cluster network interface resides in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this VPC.", + }, + "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 VPC.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this VPC. The name is unique across all VPCs in the region.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "zone": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The zone this cluster network interface resides in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this zone.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this zone.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsClusterNetworkInterfaceRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_interface", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + getClusterNetworkInterfaceOptions := &vpcv1.GetClusterNetworkInterfaceOptions{} + + getClusterNetworkInterfaceOptions.SetClusterNetworkID(d.Get("cluster_network_id").(string)) + getClusterNetworkInterfaceOptions.SetID(d.Get("cluster_network_interface_id").(string)) + + clusterNetworkInterface, _, err := vpcClient.GetClusterNetworkInterfaceWithContext(context, getClusterNetworkInterfaceOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetClusterNetworkInterfaceWithContext failed: %s", err.Error()), "(Data) ibm_is_cluster_network_interface", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(fmt.Sprintf("%s/%s", *getClusterNetworkInterfaceOptions.ClusterNetworkID, *getClusterNetworkInterfaceOptions.ID)) + + if err = d.Set("allow_ip_spoofing", clusterNetworkInterface.AllowIPSpoofing); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting allow_ip_spoofing: %s", err), "(Data) ibm_is_cluster_network_interface", "read", "set-allow_ip_spoofing").GetDiag() + } + + if err = d.Set("auto_delete", clusterNetworkInterface.AutoDelete); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting auto_delete: %s", err), "(Data) ibm_is_cluster_network_interface", "read", "set-auto_delete").GetDiag() + } + + if err = d.Set("created_at", flex.DateTimeToString(clusterNetworkInterface.CreatedAt)); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting created_at: %s", err), "(Data) ibm_is_cluster_network_interface", "read", "set-created_at").GetDiag() + } + + if err = d.Set("enable_infrastructure_nat", clusterNetworkInterface.EnableInfrastructureNat); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting enable_infrastructure_nat: %s", err), "(Data) ibm_is_cluster_network_interface", "read", "set-enable_infrastructure_nat").GetDiag() + } + + if err = d.Set("href", clusterNetworkInterface.Href); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting href: %s", err), "(Data) ibm_is_cluster_network_interface", "read", "set-href").GetDiag() + } + + lifecycleReasons := []map[string]interface{}{} + for _, lifecycleReasonsItem := range clusterNetworkInterface.LifecycleReasons { + lifecycleReasonsItemMap, err := DataSourceIBMIsClusterNetworkInterfaceClusterNetworkInterfaceLifecycleReasonToMap(&lifecycleReasonsItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_interface", "read", "lifecycle_reasons-to-map").GetDiag() + } + lifecycleReasons = append(lifecycleReasons, lifecycleReasonsItemMap) + } + if err = d.Set("lifecycle_reasons", lifecycleReasons); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting lifecycle_reasons: %s", err), "(Data) ibm_is_cluster_network_interface", "read", "set-lifecycle_reasons").GetDiag() + } + + if err = d.Set("lifecycle_state", clusterNetworkInterface.LifecycleState); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting lifecycle_state: %s", err), "(Data) ibm_is_cluster_network_interface", "read", "set-lifecycle_state").GetDiag() + } + + if !core.IsNil(clusterNetworkInterface.MacAddress) { + if err = d.Set("mac_address", clusterNetworkInterface.MacAddress); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting mac_address: %s", err), "(Data) ibm_is_cluster_network_interface", "read", "set-mac_address").GetDiag() + } + } + + if err = d.Set("name", clusterNetworkInterface.Name); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting name: %s", err), "(Data) ibm_is_cluster_network_interface", "read", "set-name").GetDiag() + } + + primaryIP := []map[string]interface{}{} + primaryIPMap, err := DataSourceIBMIsClusterNetworkInterfaceClusterNetworkSubnetReservedIPReferenceToMap(clusterNetworkInterface.PrimaryIP) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_interface", "read", "primary_ip-to-map").GetDiag() + } + primaryIP = append(primaryIP, primaryIPMap) + if err = d.Set("primary_ip", primaryIP); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting primary_ip: %s", err), "(Data) ibm_is_cluster_network_interface", "read", "set-primary_ip").GetDiag() + } + + // if !core.IsNil(clusterNetworkInterface.ProtocolStateFilteringMode) { + // if err = d.Set("protocol_state_filtering_mode", clusterNetworkInterface.ProtocolStateFilteringMode); err != nil { + // return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting protocol_state_filtering_mode: %s", err), "(Data) ibm_is_cluster_network_interface", "read", "set-protocol_state_filtering_mode").GetDiag() + // } + // } + + if err = d.Set("resource_type", clusterNetworkInterface.ResourceType); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting resource_type: %s", err), "(Data) ibm_is_cluster_network_interface", "read", "set-resource_type").GetDiag() + } + + if !core.IsNil(clusterNetworkInterface.Subnet) { + subnet := []map[string]interface{}{} + subnetMap, err := DataSourceIBMIsClusterNetworkInterfaceClusterNetworkSubnetReferenceToMap(clusterNetworkInterface.Subnet) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_interface", "read", "subnet-to-map").GetDiag() + } + subnet = append(subnet, subnetMap) + if err = d.Set("subnet", subnet); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting subnet: %s", err), "(Data) ibm_is_cluster_network_interface", "read", "set-subnet").GetDiag() + } + } + + if !core.IsNil(clusterNetworkInterface.Target) { + target := []map[string]interface{}{} + targetMap, err := DataSourceIBMIsClusterNetworkInterfaceClusterNetworkInterfaceTargetToMap(clusterNetworkInterface.Target) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_interface", "read", "target-to-map").GetDiag() + } + target = append(target, targetMap) + if err = d.Set("target", target); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting target: %s", err), "(Data) ibm_is_cluster_network_interface", "read", "set-target").GetDiag() + } + } + + vpc := []map[string]interface{}{} + vpcMap, err := DataSourceIBMIsClusterNetworkInterfaceVPCReferenceToMap(clusterNetworkInterface.VPC) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_interface", "read", "vpc-to-map").GetDiag() + } + vpc = append(vpc, vpcMap) + if err = d.Set("vpc", vpc); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting vpc: %s", err), "(Data) ibm_is_cluster_network_interface", "read", "set-vpc").GetDiag() + } + + zone := []map[string]interface{}{} + zoneMap, err := DataSourceIBMIsClusterNetworkInterfaceZoneReferenceToMap(clusterNetworkInterface.Zone) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_interface", "read", "zone-to-map").GetDiag() + } + zone = append(zone, zoneMap) + if err = d.Set("zone", zone); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting zone: %s", err), "(Data) ibm_is_cluster_network_interface", "read", "set-zone").GetDiag() + } + + return nil +} + +func DataSourceIBMIsClusterNetworkInterfaceClusterNetworkInterfaceLifecycleReasonToMap(model *vpcv1.ClusterNetworkInterfaceLifecycleReason) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["code"] = *model.Code + modelMap["message"] = *model.Message + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkInterfaceClusterNetworkSubnetReservedIPReferenceToMap(model *vpcv1.ClusterNetworkSubnetReservedIPReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["address"] = *model.Address + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsClusterNetworkInterfaceDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkInterfaceDeletedToMap(model *vpcv1.Deleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = *model.MoreInfo + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkInterfaceClusterNetworkSubnetReferenceToMap(model *vpcv1.ClusterNetworkSubnetReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsClusterNetworkInterfaceDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkInterfaceClusterNetworkInterfaceTargetToMap(model vpcv1.ClusterNetworkInterfaceTargetIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.ClusterNetworkInterfaceTargetInstanceClusterNetworkAttachmentReferenceClusterNetworkInterfaceContext); ok { + return DataSourceIBMIsClusterNetworkInterfaceClusterNetworkInterfaceTargetInstanceClusterNetworkAttachmentReferenceClusterNetworkInterfaceContextToMap(model.(*vpcv1.ClusterNetworkInterfaceTargetInstanceClusterNetworkAttachmentReferenceClusterNetworkInterfaceContext)) + } else if _, ok := model.(*vpcv1.ClusterNetworkInterfaceTarget); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.ClusterNetworkInterfaceTarget) + 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.ResourceType != nil { + modelMap["resource_type"] = *model.ResourceType + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.ClusterNetworkInterfaceTargetIntf subtype encountered") + } +} + +func DataSourceIBMIsClusterNetworkInterfaceClusterNetworkInterfaceTargetInstanceClusterNetworkAttachmentReferenceClusterNetworkInterfaceContextToMap(model *vpcv1.ClusterNetworkInterfaceTargetInstanceClusterNetworkAttachmentReferenceClusterNetworkInterfaceContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["id"] = *model.ID + modelMap["name"] = *model.Name + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkInterfaceVPCReferenceToMap(model *vpcv1.VPCReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = *model.CRN + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsClusterNetworkInterfaceDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkInterfaceZoneReferenceToMap(model *vpcv1.ZoneReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["name"] = *model.Name + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_cluster_network_interface_test.go b/ibm/service/vpc/data_source_ibm_is_cluster_network_interface_test.go new file mode 100644 index 0000000000..097cc19df8 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_cluster_network_interface_test.go @@ -0,0 +1,324 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_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" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/vpc" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/stretchr/testify/assert" +) + +func TestAccIBMIsClusterNetworkInterfaceDataSourceBasic(t *testing.T) { + clusterNetworkInterfaceClusterNetworkID := fmt.Sprintf("tf_cluster_network_id_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsClusterNetworkInterfaceDataSourceConfigBasic(clusterNetworkInterfaceClusterNetworkID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "cluster_network_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "cluster_network_interface_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "allow_ip_spoofing"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "auto_delete"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "enable_infrastructure_nat"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "lifecycle_reasons.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "mac_address"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "primary_ip.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "subnet.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "vpc.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "zone.#"), + ), + }, + }, + }) +} + +func TestAccIBMIsClusterNetworkInterfaceDataSourceAllArgs(t *testing.T) { + clusterNetworkInterfaceClusterNetworkID := fmt.Sprintf("tf_cluster_network_id_%d", acctest.RandIntRange(10, 100)) + clusterNetworkInterfaceName := fmt.Sprintf("tf_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: testAccCheckIBMIsClusterNetworkInterfaceDataSourceConfig(clusterNetworkInterfaceClusterNetworkID, clusterNetworkInterfaceName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "cluster_network_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "cluster_network_interface_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "allow_ip_spoofing"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "auto_delete"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "enable_infrastructure_nat"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "lifecycle_reasons.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "lifecycle_reasons.0.code"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "lifecycle_reasons.0.message"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "lifecycle_reasons.0.more_info"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "mac_address"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "primary_ip.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "protocol_state_filtering_mode"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "subnet.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "target.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "vpc.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "zone.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsClusterNetworkInterfaceDataSourceConfigBasic(clusterNetworkInterfaceClusterNetworkID string) string { + return fmt.Sprintf(` + data "ibm_is_cluster_network_interface" "is_cluster_network_interface_instance" { + cluster_network_id = "02c7-10274052-f495-4920-a67f-870eb3b87003" + cluster_network_interface_id = "02c7-fcc6bdf2-56f5-40ad-abce-42950007857c" + } + `) +} + +func testAccCheckIBMIsClusterNetworkInterfaceDataSourceConfig(clusterNetworkInterfaceClusterNetworkID string, clusterNetworkInterfaceName string) string { + return fmt.Sprintf(` + resource "ibm_is_cluster_network_interface" "is_cluster_network_interface_instance" { + cluster_network_id = "%s" + name = "%s" + primary_ip { + address = "10.1.0.6" + deleted { + more_info = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + } + href = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930/reserved_ips/6d353a0f-aeb1-4ae1-832e-1110d10981bb" + id = "6d353a0f-aeb1-4ae1-832e-1110d10981bb" + name = "my-cluster-network-subnet-reserved-ip" + resource_type = "cluster_network_subnet_reserved_ip" + } + subnet { + deleted { + more_info = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + } + href = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930" + id = "0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930" + name = "my-cluster-network-subnet" + resource_type = "cluster_network_subnet" + } + } + + data "ibm_is_cluster_network_interface" "is_cluster_network_interface_instance" { + cluster_network_id = ibm_is_cluster_network_interface.is_cluster_network_interface_instance.cluster_network_id + cluster_network_interface_id = ibm_is_cluster_network_interface.is_cluster_network_interface_instance.cluster_network_interface_id + } + `, clusterNetworkInterfaceClusterNetworkID, clusterNetworkInterfaceName) +} + +func TestDataSourceIBMIsClusterNetworkInterfaceClusterNetworkInterfaceLifecycleReasonToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["code"] = "resource_suspended_by_provider" + model["message"] = "The resource has been suspended. Contact IBM support with the CRN for next steps." + model["more_info"] = "https://cloud.ibm.com/apidocs/vpc#resource-suspension" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ClusterNetworkInterfaceLifecycleReason) + model.Code = core.StringPtr("resource_suspended_by_provider") + model.Message = core.StringPtr("The resource has been suspended. Contact IBM support with the CRN for next steps.") + model.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#resource-suspension") + + result, err := vpc.DataSourceIBMIsClusterNetworkInterfaceClusterNetworkInterfaceLifecycleReasonToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkInterfaceClusterNetworkSubnetReservedIPReferenceToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + deletedModel := make(map[string]interface{}) + deletedModel["more_info"] = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + + model := make(map[string]interface{}) + model["address"] = "10.1.0.6" + model["deleted"] = []map[string]interface{}{deletedModel} + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930/reserved_ips/6d353a0f-aeb1-4ae1-832e-1110d10981bb" + model["id"] = "6d353a0f-aeb1-4ae1-832e-1110d10981bb" + model["name"] = "my-cluster-network-subnet-reserved-ip" + model["resource_type"] = "cluster_network_subnet_reserved_ip" + + assert.Equal(t, result, model) + } + + deletedModel := new(vpcv1.Deleted) + deletedModel.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#deleted-resources") + + model := new(vpcv1.ClusterNetworkSubnetReservedIPReference) + model.Address = core.StringPtr("10.1.0.6") + model.Deleted = deletedModel + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930/reserved_ips/6d353a0f-aeb1-4ae1-832e-1110d10981bb") + model.ID = core.StringPtr("6d353a0f-aeb1-4ae1-832e-1110d10981bb") + model.Name = core.StringPtr("my-cluster-network-subnet-reserved-ip") + model.ResourceType = core.StringPtr("cluster_network_subnet_reserved_ip") + + result, err := vpc.DataSourceIBMIsClusterNetworkInterfaceClusterNetworkSubnetReservedIPReferenceToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkInterfaceDeletedToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["more_info"] = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.Deleted) + model.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#deleted-resources") + + result, err := vpc.DataSourceIBMIsClusterNetworkInterfaceDeletedToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkInterfaceClusterNetworkSubnetReferenceToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + deletedModel := make(map[string]interface{}) + deletedModel["more_info"] = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + + model := make(map[string]interface{}) + model["deleted"] = []map[string]interface{}{deletedModel} + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930" + model["id"] = "0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930" + model["name"] = "my-cluster-network-subnet" + model["resource_type"] = "cluster_network_subnet" + + assert.Equal(t, result, model) + } + + deletedModel := new(vpcv1.Deleted) + deletedModel.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#deleted-resources") + + model := new(vpcv1.ClusterNetworkSubnetReference) + model.Deleted = deletedModel + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930") + model.ID = core.StringPtr("0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930") + model.Name = core.StringPtr("my-cluster-network-subnet") + model.ResourceType = core.StringPtr("cluster_network_subnet") + + result, err := vpc.DataSourceIBMIsClusterNetworkInterfaceClusterNetworkSubnetReferenceToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkInterfaceClusterNetworkInterfaceTargetToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/instances/0717_e21b7391-2ca2-4ab5-84a8-b92157a633b0/cluster_network_attachments/0717-fb880975-db45-4459-8548-64e3995ac213" + model["id"] = "0717-fb880975-db45-4459-8548-64e3995ac213" + model["name"] = "my-instance-network-attachment" + model["resource_type"] = "instance_cluster_network_attachment" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ClusterNetworkInterfaceTarget) + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/instances/0717_e21b7391-2ca2-4ab5-84a8-b92157a633b0/cluster_network_attachments/0717-fb880975-db45-4459-8548-64e3995ac213") + model.ID = core.StringPtr("0717-fb880975-db45-4459-8548-64e3995ac213") + model.Name = core.StringPtr("my-instance-network-attachment") + model.ResourceType = core.StringPtr("instance_cluster_network_attachment") + + result, err := vpc.DataSourceIBMIsClusterNetworkInterfaceClusterNetworkInterfaceTargetToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkInterfaceClusterNetworkInterfaceTargetInstanceClusterNetworkAttachmentReferenceClusterNetworkInterfaceContextToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/instances/0717_e21b7391-2ca2-4ab5-84a8-b92157a633b0/cluster_network_attachments/0717-fb880975-db45-4459-8548-64e3995ac213" + model["id"] = "0717-fb880975-db45-4459-8548-64e3995ac213" + model["name"] = "my-instance-network-attachment" + model["resource_type"] = "instance_cluster_network_attachment" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ClusterNetworkInterfaceTargetInstanceClusterNetworkAttachmentReferenceClusterNetworkInterfaceContext) + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/instances/0717_e21b7391-2ca2-4ab5-84a8-b92157a633b0/cluster_network_attachments/0717-fb880975-db45-4459-8548-64e3995ac213") + model.ID = core.StringPtr("0717-fb880975-db45-4459-8548-64e3995ac213") + model.Name = core.StringPtr("my-instance-network-attachment") + model.ResourceType = core.StringPtr("instance_cluster_network_attachment") + + result, err := vpc.DataSourceIBMIsClusterNetworkInterfaceClusterNetworkInterfaceTargetInstanceClusterNetworkAttachmentReferenceClusterNetworkInterfaceContextToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkInterfaceVPCReferenceToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + deletedModel := make(map[string]interface{}) + deletedModel["more_info"] = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + + model := make(map[string]interface{}) + model["crn"] = "crn:v1:bluemix:public:is:us-south:a/aa2432b1fa4d4ace891e9b80fc104e34::vpc:r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + model["deleted"] = []map[string]interface{}{deletedModel} + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/vpcs/r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + model["id"] = "r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + model["name"] = "my-vpc" + model["resource_type"] = "vpc" + + assert.Equal(t, result, model) + } + + deletedModel := new(vpcv1.Deleted) + deletedModel.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#deleted-resources") + + model := new(vpcv1.VPCReference) + model.CRN = core.StringPtr("crn:v1:bluemix:public:is:us-south:a/aa2432b1fa4d4ace891e9b80fc104e34::vpc:r006-4727d842-f94f-4a2d-824a-9bc9b02c523b") + model.Deleted = deletedModel + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/vpcs/r006-4727d842-f94f-4a2d-824a-9bc9b02c523b") + model.ID = core.StringPtr("r006-4727d842-f94f-4a2d-824a-9bc9b02c523b") + model.Name = core.StringPtr("my-vpc") + model.ResourceType = core.StringPtr("vpc") + + result, err := vpc.DataSourceIBMIsClusterNetworkInterfaceVPCReferenceToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkInterfaceZoneReferenceToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/regions/us-south/zones/us-south-1" + model["name"] = "us-south-1" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ZoneReference) + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/regions/us-south/zones/us-south-1") + model.Name = core.StringPtr("us-south-1") + + result, err := vpc.DataSourceIBMIsClusterNetworkInterfaceZoneReferenceToMap(model) + assert.Nil(t, err) + checkResult(result) +} diff --git a/ibm/service/vpc/data_source_ibm_is_cluster_network_interfaces.go b/ibm/service/vpc/data_source_ibm_is_cluster_network_interfaces.go new file mode 100644 index 0000000000..9734880bb6 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_cluster_network_interfaces.go @@ -0,0 +1,537 @@ +// Copyright IBM Corp. 2024 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/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsClusterNetworkInterfaces() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsClusterNetworkInterfacesRead, + + Schema: map[string]*schema.Schema{ + "cluster_network_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The cluster network identifier.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Filters the collection to resources with a `name` property matching the exact specified name.", + }, + "sort": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "-created_at", + Description: "Sorts the returned collection by the specified property name in ascending order. A `-` may be prepended to the name to sort in descending order. For example, the value `-created_at` sorts the collection by the `created_at` property in descending order, and the value `name` sorts it by the `name` property in ascending order.", + }, + "interfaces": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A page of cluster network interfaces.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allow_ip_spoofing": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether source IP spoofing is allowed on this cluster network interface. If `false`, source IP spoofing is prevented on this cluster network interface. If `true`, source IP spoofing is allowed on this cluster network interface.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this cluster network interface will be automatically deleted when `target` is deleted.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the cluster network interface was created.", + }, + "enable_infrastructure_nat": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "If `true`:- The VPC infrastructure performs any needed NAT operations.- `floating_ips` must not have more than one floating IP.If `false`:- Packets are passed unchanged to/from the virtual network interface, allowing the workload to perform any needed NAT operations.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network interface.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network interface.", + }, + "lifecycle_reasons": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current `lifecycle_state` (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the cluster network interface.", + }, + "mac_address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The MAC address of the cluster network interface. May be absent if`lifecycle_state` is `pending`.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network interface. The name is unique across all interfaces in the cluster network.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The cluster network subnet reserved IP for this cluster network interface.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address is pending allocation, the value will be `0.0.0.0`.This property may [expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) to support IPv6 addresses in the future.", + }, + "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 cluster network subnet reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network subnet reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network subnet reserved IP. The name is unique across all reserved IPs in a cluster network subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + // "protocol_state_filtering_mode": &schema.Schema{ + // Type: schema.TypeString, + // Computed: true, + // Description: "The protocol state filtering mode used for this cluster network interface.Protocol state filtering monitors each network connection flowing over this cluster network interface, and drops any packets that are invalid based on the current connection state and protocol. See [Protocol state filtering mode](https://cloud.ibm.com/docs/vpc?topic=vpc-vni-about#protocol-state-filtering) for more information.The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + // }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "subnet": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + 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 cluster network subnet.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network subnet. The name is unique across all cluster network subnets in the cluster network.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "target": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The target of this cluster network interface.If absent, this cluster network interface is not attached to a target.The resources supported by this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this instance cluster network attachment.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance cluster network attachment.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this instance cluster network attachment. The name is unique across all network attachments for the instance.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "vpc": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The VPC this cluster network interface resides in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this VPC.", + }, + "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 VPC.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this VPC. The name is unique across all VPCs in the region.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "zone": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The zone this cluster network interface resides in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this zone.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this zone.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsClusterNetworkInterfacesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_interfaces", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + listClusterNetworkInterfacesOptions := &vpcv1.ListClusterNetworkInterfacesOptions{} + + listClusterNetworkInterfacesOptions.SetClusterNetworkID(d.Get("cluster_network_id").(string)) + if _, ok := d.GetOk("name"); ok { + listClusterNetworkInterfacesOptions.SetName(d.Get("name").(string)) + } + if _, ok := d.GetOk("sort"); ok { + listClusterNetworkInterfacesOptions.SetSort(d.Get("sort").(string)) + } + + var pager *vpcv1.ClusterNetworkInterfacesPager + pager, err = vpcClient.NewClusterNetworkInterfacesPager(listClusterNetworkInterfacesOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_interfaces", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + allItems, err := pager.GetAll() + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("ClusterNetworkInterfacesPager.GetAll() failed %s", err), "(Data) ibm_is_cluster_network_interfaces", "read") + log.Printf("[DEBUG] %s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(dataSourceIBMIsClusterNetworkInterfacesID(d)) + + mapSlice := []map[string]interface{}{} + for _, modelItem := range allItems { + modelMap, err := DataSourceIBMIsClusterNetworkInterfacesClusterNetworkInterfaceToMap(&modelItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_interfaces", "read", "ClusterNetworks-to-map").GetDiag() + } + mapSlice = append(mapSlice, modelMap) + } + + if err = d.Set("interfaces", mapSlice); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting interfaces %s", err), "(Data) ibm_is_cluster_network_interfaces", "read", "interfaces-set").GetDiag() + } + + return nil +} + +// dataSourceIBMIsClusterNetworkInterfacesID returns a reasonable ID for the list. +func dataSourceIBMIsClusterNetworkInterfacesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func DataSourceIBMIsClusterNetworkInterfacesClusterNetworkInterfaceToMap(model *vpcv1.ClusterNetworkInterface) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["allow_ip_spoofing"] = *model.AllowIPSpoofing + modelMap["auto_delete"] = *model.AutoDelete + modelMap["created_at"] = model.CreatedAt.String() + modelMap["enable_infrastructure_nat"] = *model.EnableInfrastructureNat + modelMap["href"] = *model.Href + modelMap["id"] = *model.ID + lifecycleReasons := []map[string]interface{}{} + for _, lifecycleReasonsItem := range model.LifecycleReasons { + lifecycleReasonsItemMap, err := DataSourceIBMIsClusterNetworkInterfacesClusterNetworkInterfaceLifecycleReasonToMap(&lifecycleReasonsItem) // #nosec G601 + if err != nil { + return modelMap, err + } + lifecycleReasons = append(lifecycleReasons, lifecycleReasonsItemMap) + } + modelMap["lifecycle_reasons"] = lifecycleReasons + modelMap["lifecycle_state"] = *model.LifecycleState + if model.MacAddress != nil { + modelMap["mac_address"] = *model.MacAddress + } + modelMap["name"] = *model.Name + primaryIPMap, err := DataSourceIBMIsClusterNetworkInterfacesClusterNetworkSubnetReservedIPReferenceToMap(model.PrimaryIP) + if err != nil { + return modelMap, err + } + modelMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + // if model.ProtocolStateFilteringMode != nil { + // modelMap["protocol_state_filtering_mode"] = *model.ProtocolStateFilteringMode + // } + modelMap["resource_type"] = *model.ResourceType + if model.Subnet != nil { + subnetMap, err := DataSourceIBMIsClusterNetworkInterfacesClusterNetworkSubnetReferenceToMap(model.Subnet) + if err != nil { + return modelMap, err + } + modelMap["subnet"] = []map[string]interface{}{subnetMap} + } + if model.Target != nil { + targetMap, err := DataSourceIBMIsClusterNetworkInterfacesClusterNetworkInterfaceTargetToMap(model.Target) + if err != nil { + return modelMap, err + } + modelMap["target"] = []map[string]interface{}{targetMap} + } + vpcMap, err := DataSourceIBMIsClusterNetworkInterfacesVPCReferenceToMap(model.VPC) + if err != nil { + return modelMap, err + } + modelMap["vpc"] = []map[string]interface{}{vpcMap} + zoneMap, err := DataSourceIBMIsClusterNetworkInterfacesZoneReferenceToMap(model.Zone) + if err != nil { + return modelMap, err + } + modelMap["zone"] = []map[string]interface{}{zoneMap} + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkInterfacesClusterNetworkInterfaceLifecycleReasonToMap(model *vpcv1.ClusterNetworkInterfaceLifecycleReason) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["code"] = *model.Code + modelMap["message"] = *model.Message + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkInterfacesClusterNetworkSubnetReservedIPReferenceToMap(model *vpcv1.ClusterNetworkSubnetReservedIPReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["address"] = *model.Address + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsClusterNetworkInterfacesDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkInterfacesDeletedToMap(model *vpcv1.Deleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = *model.MoreInfo + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkInterfacesClusterNetworkSubnetReferenceToMap(model *vpcv1.ClusterNetworkSubnetReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsClusterNetworkInterfacesDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkInterfacesClusterNetworkInterfaceTargetToMap(model vpcv1.ClusterNetworkInterfaceTargetIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.ClusterNetworkInterfaceTargetInstanceClusterNetworkAttachmentReferenceClusterNetworkInterfaceContext); ok { + return DataSourceIBMIsClusterNetworkInterfacesClusterNetworkInterfaceTargetInstanceClusterNetworkAttachmentReferenceClusterNetworkInterfaceContextToMap(model.(*vpcv1.ClusterNetworkInterfaceTargetInstanceClusterNetworkAttachmentReferenceClusterNetworkInterfaceContext)) + } else if _, ok := model.(*vpcv1.ClusterNetworkInterfaceTarget); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.ClusterNetworkInterfaceTarget) + 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.ResourceType != nil { + modelMap["resource_type"] = *model.ResourceType + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.ClusterNetworkInterfaceTargetIntf subtype encountered") + } +} + +func DataSourceIBMIsClusterNetworkInterfacesClusterNetworkInterfaceTargetInstanceClusterNetworkAttachmentReferenceClusterNetworkInterfaceContextToMap(model *vpcv1.ClusterNetworkInterfaceTargetInstanceClusterNetworkAttachmentReferenceClusterNetworkInterfaceContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["id"] = *model.ID + modelMap["name"] = *model.Name + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkInterfacesVPCReferenceToMap(model *vpcv1.VPCReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = *model.CRN + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsClusterNetworkInterfacesDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkInterfacesZoneReferenceToMap(model *vpcv1.ZoneReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["name"] = *model.Name + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_cluster_network_interfaces_test.go b/ibm/service/vpc/data_source_ibm_is_cluster_network_interfaces_test.go new file mode 100644 index 0000000000..d421399715 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_cluster_network_interfaces_test.go @@ -0,0 +1,452 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_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" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/vpc" + . "github.com/IBM-Cloud/terraform-provider-ibm/ibm/unittest" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/stretchr/testify/assert" +) + +func TestAccIBMIsClusterNetworkInterfacesDataSourceBasic(t *testing.T) { + clusterNetworkInterfaceClusterNetworkID := fmt.Sprintf("tf_cluster_network_id_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsClusterNetworkInterfacesDataSourceConfigBasic(clusterNetworkInterfaceClusterNetworkID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "cluster_network_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.allow_ip_spoofing"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.auto_delete"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.enable_infrastructure_nat"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.lifecycle_reasons.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.mac_address"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.primary_ip.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.subnet.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.target.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.vpc.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.zone.#"), + ), + }, + }, + }) +} + +func TestAccIBMIsClusterNetworkInterfacesDataSourceAllArgs(t *testing.T) { + clusterNetworkInterfaceClusterNetworkID := fmt.Sprintf("tf_cluster_network_id_%d", acctest.RandIntRange(10, 100)) + clusterNetworkInterfaceName := fmt.Sprintf("tf_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: testAccCheckIBMIsClusterNetworkInterfacesDataSourceConfig(clusterNetworkInterfaceClusterNetworkID, clusterNetworkInterfaceName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "cluster_network_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "sort"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.allow_ip_spoofing"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.auto_delete"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.enable_infrastructure_nat"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.mac_address"), + resource.TestCheckResourceAttr("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.name", clusterNetworkInterfaceName), + // resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.protocol_state_filtering_mode"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_interfaces.is_cluster_network_interfaces_instance", "interfaces.0.resource_type"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsClusterNetworkInterfacesDataSourceConfigBasic(clusterNetworkInterfaceClusterNetworkID string) string { + return fmt.Sprintf(` + + data "ibm_is_cluster_network_interfaces" "is_cluster_network_interfaces_instance" { + cluster_network_id = "02c7-10274052-f495-4920-a67f-870eb3b87003" + } + `) +} + +func testAccCheckIBMIsClusterNetworkInterfacesDataSourceConfig(clusterNetworkInterfaceClusterNetworkID string, clusterNetworkInterfaceName string) string { + return fmt.Sprintf(` + resource "ibm_is_cluster_network_interface" "is_cluster_network_interface_instance" { + cluster_network_id = "%s" + name = "%s" + primary_ip { + address = "10.1.0.6" + deleted { + more_info = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + } + href = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930/reserved_ips/6d353a0f-aeb1-4ae1-832e-1110d10981bb" + id = "6d353a0f-aeb1-4ae1-832e-1110d10981bb" + name = "my-cluster-network-subnet-reserved-ip" + resource_type = "cluster_network_subnet_reserved_ip" + } + subnet { + deleted { + more_info = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + } + href = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930" + id = "0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930" + name = "my-cluster-network-subnet" + resource_type = "cluster_network_subnet" + } + } + + data "ibm_is_cluster_network_interfaces" "is_cluster_network_interfaces_instance" { + cluster_network_id = ibm_is_cluster_network_interface.is_cluster_network_interface_instance.cluster_network_id + name = ibm_is_cluster_network_interface.is_cluster_network_interface_instance.name + sort = "name" + } + `, clusterNetworkInterfaceClusterNetworkID, clusterNetworkInterfaceName) +} + +func TestDataSourceIBMIsClusterNetworkInterfacesClusterNetworkInterfaceToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + clusterNetworkInterfaceLifecycleReasonModel := make(map[string]interface{}) + clusterNetworkInterfaceLifecycleReasonModel["code"] = "resource_suspended_by_provider" + clusterNetworkInterfaceLifecycleReasonModel["message"] = "The resource has been suspended. Contact IBM support with the CRN for next steps." + clusterNetworkInterfaceLifecycleReasonModel["more_info"] = "https://cloud.ibm.com/apidocs/vpc#resource-suspension" + + deletedModel := make(map[string]interface{}) + deletedModel["more_info"] = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + + clusterNetworkSubnetReservedIPReferenceModel := make(map[string]interface{}) + clusterNetworkSubnetReservedIPReferenceModel["address"] = "10.1.0.6" + clusterNetworkSubnetReservedIPReferenceModel["deleted"] = []map[string]interface{}{deletedModel} + clusterNetworkSubnetReservedIPReferenceModel["href"] = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930/reserved_ips/63341ffa-1037-4b50-be40-676e3e9ac0c7" + clusterNetworkSubnetReservedIPReferenceModel["id"] = "63341ffa-1037-4b50-be40-676e3e9ac0c7" + clusterNetworkSubnetReservedIPReferenceModel["name"] = "my-cluster-network-subnet-reserved-ip" + clusterNetworkSubnetReservedIPReferenceModel["resource_type"] = "cluster_network_subnet_reserved_ip" + + clusterNetworkSubnetReferenceModel := make(map[string]interface{}) + clusterNetworkSubnetReferenceModel["deleted"] = []map[string]interface{}{deletedModel} + clusterNetworkSubnetReferenceModel["href"] = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930" + clusterNetworkSubnetReferenceModel["id"] = "0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930" + clusterNetworkSubnetReferenceModel["name"] = "my-cluster-network-subnet" + clusterNetworkSubnetReferenceModel["resource_type"] = "cluster_network_subnet" + + clusterNetworkInterfaceTargetModel := make(map[string]interface{}) + clusterNetworkInterfaceTargetModel["href"] = "https://us-south.iaas.cloud.ibm.com/v1/instances/0717_e21b7391-2ca2-4ab5-84a8-b92157a633b0/cluster_network_attachments/0717-fb880975-db45-4459-8548-64e3995ac213" + clusterNetworkInterfaceTargetModel["id"] = "0717-fb880975-db45-4459-8548-64e3995ac213" + clusterNetworkInterfaceTargetModel["name"] = "my-instance-network-attachment" + clusterNetworkInterfaceTargetModel["resource_type"] = "instance_cluster_network_attachment" + + vpcReferenceModel := make(map[string]interface{}) + vpcReferenceModel["crn"] = "crn:v1:bluemix:public:is:us-south:a/aa2432b1fa4d4ace891e9b80fc104e34::vpc:r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + vpcReferenceModel["deleted"] = []map[string]interface{}{deletedModel} + vpcReferenceModel["href"] = "https://us-south.iaas.cloud.ibm.com/v1/vpcs/r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + vpcReferenceModel["id"] = "r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + vpcReferenceModel["name"] = "my-vpc" + vpcReferenceModel["resource_type"] = "vpc" + + zoneReferenceModel := make(map[string]interface{}) + zoneReferenceModel["href"] = "https://us-south.iaas.cloud.ibm.com/v1/regions/us-south/zones/us-south-1" + zoneReferenceModel["name"] = "us-south-1" + + model := make(map[string]interface{}) + model["allow_ip_spoofing"] = true + model["auto_delete"] = false + model["created_at"] = "2019-01-01T12:00:00.000Z" + model["enable_infrastructure_nat"] = false + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/interfaces/0717-ffc092f7-5d02-4b93-ab69-26860529b9fb" + model["id"] = "0717-ffc092f7-5d02-4b93-ab69-26860529b9fb" + model["lifecycle_reasons"] = []map[string]interface{}{clusterNetworkInterfaceLifecycleReasonModel} + model["lifecycle_state"] = "stable" + model["mac_address"] = "02:00:4D:45:45:4D" + model["name"] = "my-cluster-network-interface" + model["primary_ip"] = []map[string]interface{}{clusterNetworkSubnetReservedIPReferenceModel} + // model["protocol_state_filtering_mode"] = "enabled" + model["resource_type"] = "cluster_network_interface" + model["subnet"] = []map[string]interface{}{clusterNetworkSubnetReferenceModel} + model["target"] = []map[string]interface{}{clusterNetworkInterfaceTargetModel} + model["vpc"] = []map[string]interface{}{vpcReferenceModel} + model["zone"] = []map[string]interface{}{zoneReferenceModel} + + assert.Equal(t, result, model) + } + + clusterNetworkInterfaceLifecycleReasonModel := new(vpcv1.ClusterNetworkInterfaceLifecycleReason) + clusterNetworkInterfaceLifecycleReasonModel.Code = core.StringPtr("resource_suspended_by_provider") + clusterNetworkInterfaceLifecycleReasonModel.Message = core.StringPtr("The resource has been suspended. Contact IBM support with the CRN for next steps.") + clusterNetworkInterfaceLifecycleReasonModel.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#resource-suspension") + + deletedModel := new(vpcv1.Deleted) + deletedModel.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#deleted-resources") + + clusterNetworkSubnetReservedIPReferenceModel := new(vpcv1.ClusterNetworkSubnetReservedIPReference) + clusterNetworkSubnetReservedIPReferenceModel.Address = core.StringPtr("10.1.0.6") + clusterNetworkSubnetReservedIPReferenceModel.Deleted = deletedModel + clusterNetworkSubnetReservedIPReferenceModel.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930/reserved_ips/63341ffa-1037-4b50-be40-676e3e9ac0c7") + clusterNetworkSubnetReservedIPReferenceModel.ID = core.StringPtr("63341ffa-1037-4b50-be40-676e3e9ac0c7") + clusterNetworkSubnetReservedIPReferenceModel.Name = core.StringPtr("my-cluster-network-subnet-reserved-ip") + clusterNetworkSubnetReservedIPReferenceModel.ResourceType = core.StringPtr("cluster_network_subnet_reserved_ip") + + clusterNetworkSubnetReferenceModel := new(vpcv1.ClusterNetworkSubnetReference) + clusterNetworkSubnetReferenceModel.Deleted = deletedModel + clusterNetworkSubnetReferenceModel.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930") + clusterNetworkSubnetReferenceModel.ID = core.StringPtr("0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930") + clusterNetworkSubnetReferenceModel.Name = core.StringPtr("my-cluster-network-subnet") + clusterNetworkSubnetReferenceModel.ResourceType = core.StringPtr("cluster_network_subnet") + + clusterNetworkInterfaceTargetModel := new(vpcv1.ClusterNetworkInterfaceTargetInstanceClusterNetworkAttachmentReferenceClusterNetworkInterfaceContext) + clusterNetworkInterfaceTargetModel.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/instances/0717_e21b7391-2ca2-4ab5-84a8-b92157a633b0/cluster_network_attachments/0717-fb880975-db45-4459-8548-64e3995ac213") + clusterNetworkInterfaceTargetModel.ID = core.StringPtr("0717-fb880975-db45-4459-8548-64e3995ac213") + clusterNetworkInterfaceTargetModel.Name = core.StringPtr("my-instance-network-attachment") + clusterNetworkInterfaceTargetModel.ResourceType = core.StringPtr("instance_cluster_network_attachment") + + vpcReferenceModel := new(vpcv1.VPCReference) + vpcReferenceModel.CRN = core.StringPtr("crn:v1:bluemix:public:is:us-south:a/aa2432b1fa4d4ace891e9b80fc104e34::vpc:r006-4727d842-f94f-4a2d-824a-9bc9b02c523b") + vpcReferenceModel.Deleted = deletedModel + vpcReferenceModel.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/vpcs/r006-4727d842-f94f-4a2d-824a-9bc9b02c523b") + vpcReferenceModel.ID = core.StringPtr("r006-4727d842-f94f-4a2d-824a-9bc9b02c523b") + vpcReferenceModel.Name = core.StringPtr("my-vpc") + vpcReferenceModel.ResourceType = core.StringPtr("vpc") + + zoneReferenceModel := new(vpcv1.ZoneReference) + zoneReferenceModel.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/regions/us-south/zones/us-south-1") + zoneReferenceModel.Name = core.StringPtr("us-south-1") + + model := new(vpcv1.ClusterNetworkInterface) + model.AllowIPSpoofing = core.BoolPtr(true) + model.AutoDelete = core.BoolPtr(false) + model.CreatedAt = CreateMockDateTime("2019-01-01T12:00:00.000Z") + model.EnableInfrastructureNat = core.BoolPtr(false) + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/interfaces/0717-ffc092f7-5d02-4b93-ab69-26860529b9fb") + model.ID = core.StringPtr("0717-ffc092f7-5d02-4b93-ab69-26860529b9fb") + model.LifecycleReasons = []vpcv1.ClusterNetworkInterfaceLifecycleReason{*clusterNetworkInterfaceLifecycleReasonModel} + model.LifecycleState = core.StringPtr("stable") + model.MacAddress = core.StringPtr("02:00:4D:45:45:4D") + model.Name = core.StringPtr("my-cluster-network-interface") + model.PrimaryIP = clusterNetworkSubnetReservedIPReferenceModel + // model.ProtocolStateFilteringMode = core.StringPtr("enabled") + model.ResourceType = core.StringPtr("cluster_network_interface") + model.Subnet = clusterNetworkSubnetReferenceModel + model.Target = clusterNetworkInterfaceTargetModel + model.VPC = vpcReferenceModel + model.Zone = zoneReferenceModel + + result, err := vpc.DataSourceIBMIsClusterNetworkInterfacesClusterNetworkInterfaceToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkInterfacesClusterNetworkInterfaceLifecycleReasonToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["code"] = "resource_suspended_by_provider" + model["message"] = "The resource has been suspended. Contact IBM support with the CRN for next steps." + model["more_info"] = "https://cloud.ibm.com/apidocs/vpc#resource-suspension" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ClusterNetworkInterfaceLifecycleReason) + model.Code = core.StringPtr("resource_suspended_by_provider") + model.Message = core.StringPtr("The resource has been suspended. Contact IBM support with the CRN for next steps.") + model.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#resource-suspension") + + result, err := vpc.DataSourceIBMIsClusterNetworkInterfacesClusterNetworkInterfaceLifecycleReasonToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkInterfacesClusterNetworkSubnetReservedIPReferenceToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + deletedModel := make(map[string]interface{}) + deletedModel["more_info"] = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + + model := make(map[string]interface{}) + model["address"] = "10.1.0.6" + model["deleted"] = []map[string]interface{}{deletedModel} + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930/reserved_ips/6d353a0f-aeb1-4ae1-832e-1110d10981bb" + model["id"] = "6d353a0f-aeb1-4ae1-832e-1110d10981bb" + model["name"] = "my-cluster-network-subnet-reserved-ip" + model["resource_type"] = "cluster_network_subnet_reserved_ip" + + assert.Equal(t, result, model) + } + + deletedModel := new(vpcv1.Deleted) + deletedModel.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#deleted-resources") + + model := new(vpcv1.ClusterNetworkSubnetReservedIPReference) + model.Address = core.StringPtr("10.1.0.6") + model.Deleted = deletedModel + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930/reserved_ips/6d353a0f-aeb1-4ae1-832e-1110d10981bb") + model.ID = core.StringPtr("6d353a0f-aeb1-4ae1-832e-1110d10981bb") + model.Name = core.StringPtr("my-cluster-network-subnet-reserved-ip") + model.ResourceType = core.StringPtr("cluster_network_subnet_reserved_ip") + + result, err := vpc.DataSourceIBMIsClusterNetworkInterfacesClusterNetworkSubnetReservedIPReferenceToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkInterfacesDeletedToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["more_info"] = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.Deleted) + model.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#deleted-resources") + + result, err := vpc.DataSourceIBMIsClusterNetworkInterfacesDeletedToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkInterfacesClusterNetworkSubnetReferenceToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + deletedModel := make(map[string]interface{}) + deletedModel["more_info"] = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + + model := make(map[string]interface{}) + model["deleted"] = []map[string]interface{}{deletedModel} + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930" + model["id"] = "0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930" + model["name"] = "my-cluster-network-subnet" + model["resource_type"] = "cluster_network_subnet" + + assert.Equal(t, result, model) + } + + deletedModel := new(vpcv1.Deleted) + deletedModel.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#deleted-resources") + + model := new(vpcv1.ClusterNetworkSubnetReference) + model.Deleted = deletedModel + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930") + model.ID = core.StringPtr("0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930") + model.Name = core.StringPtr("my-cluster-network-subnet") + model.ResourceType = core.StringPtr("cluster_network_subnet") + + result, err := vpc.DataSourceIBMIsClusterNetworkInterfacesClusterNetworkSubnetReferenceToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkInterfacesClusterNetworkInterfaceTargetToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/instances/0717_e21b7391-2ca2-4ab5-84a8-b92157a633b0/cluster_network_attachments/0717-fb880975-db45-4459-8548-64e3995ac213" + model["id"] = "0717-fb880975-db45-4459-8548-64e3995ac213" + model["name"] = "my-instance-network-attachment" + model["resource_type"] = "instance_cluster_network_attachment" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ClusterNetworkInterfaceTarget) + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/instances/0717_e21b7391-2ca2-4ab5-84a8-b92157a633b0/cluster_network_attachments/0717-fb880975-db45-4459-8548-64e3995ac213") + model.ID = core.StringPtr("0717-fb880975-db45-4459-8548-64e3995ac213") + model.Name = core.StringPtr("my-instance-network-attachment") + model.ResourceType = core.StringPtr("instance_cluster_network_attachment") + + result, err := vpc.DataSourceIBMIsClusterNetworkInterfacesClusterNetworkInterfaceTargetToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkInterfacesClusterNetworkInterfaceTargetInstanceClusterNetworkAttachmentReferenceClusterNetworkInterfaceContextToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/instances/0717_e21b7391-2ca2-4ab5-84a8-b92157a633b0/cluster_network_attachments/0717-fb880975-db45-4459-8548-64e3995ac213" + model["id"] = "0717-fb880975-db45-4459-8548-64e3995ac213" + model["name"] = "my-instance-network-attachment" + model["resource_type"] = "instance_cluster_network_attachment" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ClusterNetworkInterfaceTargetInstanceClusterNetworkAttachmentReferenceClusterNetworkInterfaceContext) + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/instances/0717_e21b7391-2ca2-4ab5-84a8-b92157a633b0/cluster_network_attachments/0717-fb880975-db45-4459-8548-64e3995ac213") + model.ID = core.StringPtr("0717-fb880975-db45-4459-8548-64e3995ac213") + model.Name = core.StringPtr("my-instance-network-attachment") + model.ResourceType = core.StringPtr("instance_cluster_network_attachment") + + result, err := vpc.DataSourceIBMIsClusterNetworkInterfacesClusterNetworkInterfaceTargetInstanceClusterNetworkAttachmentReferenceClusterNetworkInterfaceContextToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkInterfacesVPCReferenceToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + deletedModel := make(map[string]interface{}) + deletedModel["more_info"] = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + + model := make(map[string]interface{}) + model["crn"] = "crn:v1:bluemix:public:is:us-south:a/aa2432b1fa4d4ace891e9b80fc104e34::vpc:r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + model["deleted"] = []map[string]interface{}{deletedModel} + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/vpcs/r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + model["id"] = "r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + model["name"] = "my-vpc" + model["resource_type"] = "vpc" + + assert.Equal(t, result, model) + } + + deletedModel := new(vpcv1.Deleted) + deletedModel.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#deleted-resources") + + model := new(vpcv1.VPCReference) + model.CRN = core.StringPtr("crn:v1:bluemix:public:is:us-south:a/aa2432b1fa4d4ace891e9b80fc104e34::vpc:r006-4727d842-f94f-4a2d-824a-9bc9b02c523b") + model.Deleted = deletedModel + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/vpcs/r006-4727d842-f94f-4a2d-824a-9bc9b02c523b") + model.ID = core.StringPtr("r006-4727d842-f94f-4a2d-824a-9bc9b02c523b") + model.Name = core.StringPtr("my-vpc") + model.ResourceType = core.StringPtr("vpc") + + result, err := vpc.DataSourceIBMIsClusterNetworkInterfacesVPCReferenceToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkInterfacesZoneReferenceToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/regions/us-south/zones/us-south-1" + model["name"] = "us-south-1" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ZoneReference) + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/regions/us-south/zones/us-south-1") + model.Name = core.StringPtr("us-south-1") + + result, err := vpc.DataSourceIBMIsClusterNetworkInterfacesZoneReferenceToMap(model) + assert.Nil(t, err) + checkResult(result) +} diff --git a/ibm/service/vpc/data_source_ibm_is_cluster_network_profile.go b/ibm/service/vpc/data_source_ibm_is_cluster_network_profile.go new file mode 100644 index 0000000000..3acf8ea15a --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_cluster_network_profile.go @@ -0,0 +1,164 @@ +// Copyright IBM Corp. 2024 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/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsClusterNetworkProfile() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsClusterNetworkProfileRead, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The cluster network profile name.", + }, + "family": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The product family this cluster network profile belongs to.The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network profile.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "supported_instance_profiles": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The instance profiles that support this cluster network profile.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual server instance profile.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this virtual server instance profile.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "zones": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Zones in this region that support this cluster network profile.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this zone.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this zone.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsClusterNetworkProfileRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_profile", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + getClusterNetworkProfileOptions := &vpcv1.GetClusterNetworkProfileOptions{} + + getClusterNetworkProfileOptions.SetName(d.Get("name").(string)) + + clusterNetworkProfile, _, err := vpcClient.GetClusterNetworkProfileWithContext(context, getClusterNetworkProfileOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetClusterNetworkProfileWithContext failed: %s", err.Error()), "(Data) ibm_is_cluster_network_profile", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(*clusterNetworkProfile.Name) + + if err = d.Set("family", clusterNetworkProfile.Family); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting family: %s", err), "(Data) ibm_is_cluster_network_profile", "read", "set-family").GetDiag() + } + + if err = d.Set("href", clusterNetworkProfile.Href); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting href: %s", err), "(Data) ibm_is_cluster_network_profile", "read", "set-href").GetDiag() + } + + if err = d.Set("resource_type", clusterNetworkProfile.ResourceType); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting resource_type: %s", err), "(Data) ibm_is_cluster_network_profile", "read", "set-resource_type").GetDiag() + } + + supportedInstanceProfiles := []map[string]interface{}{} + for _, supportedInstanceProfilesItem := range clusterNetworkProfile.SupportedInstanceProfiles { + supportedInstanceProfilesItemMap, err := DataSourceIBMIsClusterNetworkProfileInstanceProfileReferenceToMap(&supportedInstanceProfilesItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_profile", "read", "supported_instance_profiles-to-map").GetDiag() + } + supportedInstanceProfiles = append(supportedInstanceProfiles, supportedInstanceProfilesItemMap) + } + if err = d.Set("supported_instance_profiles", supportedInstanceProfiles); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting supported_instance_profiles: %s", err), "(Data) ibm_is_cluster_network_profile", "read", "set-supported_instance_profiles").GetDiag() + } + + zones := []map[string]interface{}{} + for _, zonesItem := range clusterNetworkProfile.Zones { + zonesItemMap, err := DataSourceIBMIsClusterNetworkProfileZoneReferenceToMap(&zonesItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_profile", "read", "zones-to-map").GetDiag() + } + zones = append(zones, zonesItemMap) + } + if err = d.Set("zones", zones); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting zones: %s", err), "(Data) ibm_is_cluster_network_profile", "read", "set-zones").GetDiag() + } + + return nil +} + +func DataSourceIBMIsClusterNetworkProfileInstanceProfileReferenceToMap(model *vpcv1.InstanceProfileReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["name"] = *model.Name + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkProfileZoneReferenceToMap(model *vpcv1.ZoneReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["name"] = *model.Name + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_cluster_network_profile_test.go b/ibm/service/vpc/data_source_ibm_is_cluster_network_profile_test.go new file mode 100644 index 0000000000..b3c887ab8e --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_cluster_network_profile_test.go @@ -0,0 +1,87 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/vpc" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/stretchr/testify/assert" +) + +func TestAccIBMIsClusterNetworkProfileDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsClusterNetworkProfileDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_profile.is_cluster_network_profile_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_profile.is_cluster_network_profile_instance", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_profile.is_cluster_network_profile_instance", "family"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_profile.is_cluster_network_profile_instance", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_profile.is_cluster_network_profile_instance", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_profile.is_cluster_network_profile_instance", "supported_instance_profiles.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_profile.is_cluster_network_profile_instance", "supported_instance_profiles.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_profile.is_cluster_network_profile_instance", "supported_instance_profiles.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_profile.is_cluster_network_profile_instance", "supported_instance_profiles.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_profile.is_cluster_network_profile_instance", "zones.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsClusterNetworkProfileDataSourceConfigBasic() string { + return fmt.Sprintf(` + data "ibm_is_cluster_network_profile" "is_cluster_network_profile_instance" { + name = "%s" + } + `, acc.ISClusterNetworkProfileName) +} + +func TestDataSourceIBMIsClusterNetworkProfileInstanceProfileReferenceToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/instance/profiles/bx2-4x16" + model["name"] = "bx2-4x16" + model["resource_type"] = "instance_profile" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.InstanceProfileReference) + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/instance/profiles/bx2-4x16") + model.Name = core.StringPtr("bx2-4x16") + model.ResourceType = core.StringPtr("instance_profile") + + result, err := vpc.DataSourceIBMIsClusterNetworkProfileInstanceProfileReferenceToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkProfileZoneReferenceToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/regions/us-south/zones/us-south-1" + model["name"] = "us-south-1" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ZoneReference) + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/regions/us-south/zones/us-south-1") + model.Name = core.StringPtr("us-south-1") + + result, err := vpc.DataSourceIBMIsClusterNetworkProfileZoneReferenceToMap(model) + assert.Nil(t, err) + checkResult(result) +} diff --git a/ibm/service/vpc/data_source_ibm_is_cluster_network_profiles.go b/ibm/service/vpc/data_source_ibm_is_cluster_network_profiles.go new file mode 100644 index 0000000000..9f3a64f134 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_cluster_network_profiles.go @@ -0,0 +1,189 @@ +// Copyright IBM Corp. 2024 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/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsClusterNetworkProfiles() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsClusterNetworkProfilesRead, + + Schema: map[string]*schema.Schema{ + "profiles": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A page of cluster network profiles.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "family": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The product family this cluster network profile belongs to.The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network profile.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this cluster network profile.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "supported_instance_profiles": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The instance profiles that support this cluster network profile.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual server instance profile.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this virtual server instance profile.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "zones": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "Zones in this region that support this cluster network profile.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this zone.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this zone.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsClusterNetworkProfilesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_profiles", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + listClusterNetworkProfilesOptions := &vpcv1.ListClusterNetworkProfilesOptions{} + + var pager *vpcv1.ClusterNetworkProfilesPager + pager, err = vpcClient.NewClusterNetworkProfilesPager(listClusterNetworkProfilesOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_profiles", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + allItems, err := pager.GetAll() + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("ClusterNetworkProfilesPager.GetAll() failed %s", err), "(Data) ibm_is_cluster_network_profiles", "read") + log.Printf("[DEBUG] %s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(dataSourceIBMIsClusterNetworkProfilesID(d)) + + mapSlice := []map[string]interface{}{} + for _, modelItem := range allItems { + modelMap, err := DataSourceIBMIsClusterNetworkProfilesClusterNetworkProfileToMap(&modelItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_profiles", "read", "ClusterNetworks-to-map").GetDiag() + } + mapSlice = append(mapSlice, modelMap) + } + + if err = d.Set("profiles", mapSlice); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting profiles %s", err), "(Data) ibm_is_cluster_network_profiles", "read", "profiles-set").GetDiag() + } + + return nil +} + +// dataSourceIBMIsClusterNetworkProfilesID returns a reasonable ID for the list. +func dataSourceIBMIsClusterNetworkProfilesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func DataSourceIBMIsClusterNetworkProfilesClusterNetworkProfileToMap(model *vpcv1.ClusterNetworkProfile) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["family"] = *model.Family + modelMap["href"] = *model.Href + modelMap["name"] = *model.Name + modelMap["resource_type"] = *model.ResourceType + supportedInstanceProfiles := []map[string]interface{}{} + for _, supportedInstanceProfilesItem := range model.SupportedInstanceProfiles { + supportedInstanceProfilesItemMap, err := DataSourceIBMIsClusterNetworkProfilesInstanceProfileReferenceToMap(&supportedInstanceProfilesItem) // #nosec G601 + if err != nil { + return modelMap, err + } + supportedInstanceProfiles = append(supportedInstanceProfiles, supportedInstanceProfilesItemMap) + } + modelMap["supported_instance_profiles"] = supportedInstanceProfiles + zones := []map[string]interface{}{} + for _, zonesItem := range model.Zones { + zonesItemMap, err := DataSourceIBMIsClusterNetworkProfilesZoneReferenceToMap(&zonesItem) // #nosec G601 + if err != nil { + return modelMap, err + } + zones = append(zones, zonesItemMap) + } + modelMap["zones"] = zones + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkProfilesInstanceProfileReferenceToMap(model *vpcv1.InstanceProfileReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["name"] = *model.Name + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkProfilesZoneReferenceToMap(model *vpcv1.ZoneReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["name"] = *model.Name + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_cluster_network_profiles_test.go b/ibm/service/vpc/data_source_ibm_is_cluster_network_profiles_test.go new file mode 100644 index 0000000000..d7edf24b50 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_cluster_network_profiles_test.go @@ -0,0 +1,45 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMIsClusterNetworkProfilesDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsClusterNetworkProfilesDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_profiles.is_cluster_network_profiles_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_profiles.is_cluster_network_profiles_instance", "profiles.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_profiles.is_cluster_network_profiles_instance", "profiles.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_profiles.is_cluster_network_profiles_instance", "profiles.0.family"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_profiles.is_cluster_network_profiles_instance", "profiles.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_profiles.is_cluster_network_profiles_instance", "profiles.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_profiles.is_cluster_network_profiles_instance", "profiles.0.supported_instance_profiles.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_profiles.is_cluster_network_profiles_instance", "profiles.0.supported_instance_profiles.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_profiles.is_cluster_network_profiles_instance", "profiles.0.supported_instance_profiles.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_profiles.is_cluster_network_profiles_instance", "profiles.0.supported_instance_profiles.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_profiles.is_cluster_network_profiles_instance", "profiles.0.zones.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsClusterNetworkProfilesDataSourceConfigBasic() string { + return fmt.Sprintf(` + data "ibm_is_cluster_network_profiles" "is_cluster_network_profiles_instance" { + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_cluster_network_subnet.go b/ibm/service/vpc/data_source_ibm_is_cluster_network_subnet.go new file mode 100644 index 0000000000..0ad8f109f6 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_cluster_network_subnet.go @@ -0,0 +1,188 @@ +// Copyright IBM Corp. 2024 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/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsClusterNetworkSubnet() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsClusterNetworkSubnetRead, + + Schema: map[string]*schema.Schema{ + "cluster_network_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The cluster network identifier.", + }, + "cluster_network_subnet_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The cluster network subnet identifier.", + }, + "available_ipv4_address_count": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The number of IPv4 addresses in this cluster network subnet that are not in use, and have not been reserved by the user or the provider.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the cluster network subnet was created.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network subnet.", + }, + "ip_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP version for this cluster network subnet.The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "ipv4_cidr_block": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IPv4 range of this cluster network subnet, expressed in CIDR format.", + }, + "lifecycle_reasons": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current `lifecycle_state` (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the cluster network subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network subnet. The name is unique across all cluster network subnets in the cluster network.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "total_ipv4_address_count": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The total number of IPv4 addresses in this cluster network subnet.Note: This is calculated as 2(32 - prefix length). For example, the prefix length `/24` gives:
2(32 - 24) = 28 = 256 addresses.", + }, + }, + } +} + +func dataSourceIBMIsClusterNetworkSubnetRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_subnet", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + getClusterNetworkSubnetOptions := &vpcv1.GetClusterNetworkSubnetOptions{} + + getClusterNetworkSubnetOptions.SetClusterNetworkID(d.Get("cluster_network_id").(string)) + getClusterNetworkSubnetOptions.SetID(d.Get("cluster_network_subnet_id").(string)) + + clusterNetworkSubnet, _, err := vpcClient.GetClusterNetworkSubnetWithContext(context, getClusterNetworkSubnetOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetClusterNetworkSubnetWithContext failed: %s", err.Error()), "(Data) ibm_is_cluster_network_subnet", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(fmt.Sprintf("%s/%s", *getClusterNetworkSubnetOptions.ClusterNetworkID, *getClusterNetworkSubnetOptions.ID)) + + if err = d.Set("available_ipv4_address_count", flex.IntValue(clusterNetworkSubnet.AvailableIpv4AddressCount)); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting available_ipv4_address_count: %s", err), "(Data) ibm_is_cluster_network_subnet", "read", "set-available_ipv4_address_count").GetDiag() + } + + if err = d.Set("created_at", flex.DateTimeToString(clusterNetworkSubnet.CreatedAt)); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting created_at: %s", err), "(Data) ibm_is_cluster_network_subnet", "read", "set-created_at").GetDiag() + } + + if err = d.Set("href", clusterNetworkSubnet.Href); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting href: %s", err), "(Data) ibm_is_cluster_network_subnet", "read", "set-href").GetDiag() + } + + if err = d.Set("ip_version", clusterNetworkSubnet.IPVersion); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting ip_version: %s", err), "(Data) ibm_is_cluster_network_subnet", "read", "set-ip_version").GetDiag() + } + + if err = d.Set("ipv4_cidr_block", clusterNetworkSubnet.Ipv4CIDRBlock); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting ipv4_cidr_block: %s", err), "(Data) ibm_is_cluster_network_subnet", "read", "set-ipv4_cidr_block").GetDiag() + } + + lifecycleReasons := []map[string]interface{}{} + for _, lifecycleReasonsItem := range clusterNetworkSubnet.LifecycleReasons { + lifecycleReasonsItemMap, err := DataSourceIBMIsClusterNetworkSubnetClusterNetworkSubnetLifecycleReasonToMap(&lifecycleReasonsItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_subnet", "read", "lifecycle_reasons-to-map").GetDiag() + } + lifecycleReasons = append(lifecycleReasons, lifecycleReasonsItemMap) + } + if err = d.Set("lifecycle_reasons", lifecycleReasons); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting lifecycle_reasons: %s", err), "(Data) ibm_is_cluster_network_subnet", "read", "set-lifecycle_reasons").GetDiag() + } + + if err = d.Set("lifecycle_state", clusterNetworkSubnet.LifecycleState); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting lifecycle_state: %s", err), "(Data) ibm_is_cluster_network_subnet", "read", "set-lifecycle_state").GetDiag() + } + + if err = d.Set("name", clusterNetworkSubnet.Name); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting name: %s", err), "(Data) ibm_is_cluster_network_subnet", "read", "set-name").GetDiag() + } + + if err = d.Set("resource_type", clusterNetworkSubnet.ResourceType); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting resource_type: %s", err), "(Data) ibm_is_cluster_network_subnet", "read", "set-resource_type").GetDiag() + } + + if err = d.Set("total_ipv4_address_count", flex.IntValue(clusterNetworkSubnet.TotalIpv4AddressCount)); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting total_ipv4_address_count: %s", err), "(Data) ibm_is_cluster_network_subnet", "read", "set-total_ipv4_address_count").GetDiag() + } + + return nil +} + +func DataSourceIBMIsClusterNetworkSubnetClusterNetworkSubnetLifecycleReasonToMap(model *vpcv1.ClusterNetworkSubnetLifecycleReason) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["code"] = *model.Code + modelMap["message"] = *model.Message + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_cluster_network_subnet_reserved_ip.go b/ibm/service/vpc/data_source_ibm_is_cluster_network_subnet_reserved_ip.go new file mode 100644 index 0000000000..ea2e8109a8 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_cluster_network_subnet_reserved_ip.go @@ -0,0 +1,294 @@ +// Copyright IBM Corp. 2024 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/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsClusterNetworkSubnetReservedIP() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsClusterNetworkSubnetReservedIPRead, + + Schema: map[string]*schema.Schema{ + "cluster_network_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The cluster network identifier.", + }, + "cluster_network_subnet_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The cluster network subnet identifier.", + }, + "cluster_network_subnet_reserved_ip_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The cluster network subnet reserved IP identifier.", + }, + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address is pending allocation, the value will be `0.0.0.0`.This property may [expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) to support IPv6 addresses in the future.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this cluster network subnet reserved IP member will be automatically deleted when either `target` is deleted, or the cluster network subnet reserved IP is unbound.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the cluster network subnet reserved IP was created.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network subnet reserved IP.", + }, + "lifecycle_reasons": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current `lifecycle_state` (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the cluster network subnet reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network subnet reserved IP. The name is unique across all reserved IPs in a cluster network subnet.", + }, + "owner": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The owner of the cluster network subnet reserved IPThe enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "target": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The target this cluster network subnet reserved IP is bound to.If absent, this cluster network subnet reserved IP is provider-owned or unbound.", + 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 cluster network interface.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network interface.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network interface. The name is unique across all interfaces in the cluster network.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsClusterNetworkSubnetReservedIPRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_subnet_reserved_ip", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + getClusterNetworkSubnetReservedIPOptions := &vpcv1.GetClusterNetworkSubnetReservedIPOptions{} + + getClusterNetworkSubnetReservedIPOptions.SetClusterNetworkID(d.Get("cluster_network_id").(string)) + getClusterNetworkSubnetReservedIPOptions.SetClusterNetworkSubnetID(d.Get("cluster_network_subnet_id").(string)) + getClusterNetworkSubnetReservedIPOptions.SetID(d.Get("cluster_network_subnet_reserved_ip_id").(string)) + + clusterNetworkSubnetReservedIP, _, err := vpcClient.GetClusterNetworkSubnetReservedIPWithContext(context, getClusterNetworkSubnetReservedIPOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetClusterNetworkSubnetReservedIPWithContext failed: %s", err.Error()), "(Data) ibm_is_cluster_network_subnet_reserved_ip", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(fmt.Sprintf("%s/%s/%s", *getClusterNetworkSubnetReservedIPOptions.ClusterNetworkID, *getClusterNetworkSubnetReservedIPOptions.ClusterNetworkSubnetID, *getClusterNetworkSubnetReservedIPOptions.ID)) + + if err = d.Set("address", clusterNetworkSubnetReservedIP.Address); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting address: %s", err), "(Data) ibm_is_cluster_network_subnet_reserved_ip", "read", "set-address").GetDiag() + } + + if err = d.Set("auto_delete", clusterNetworkSubnetReservedIP.AutoDelete); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting auto_delete: %s", err), "(Data) ibm_is_cluster_network_subnet_reserved_ip", "read", "set-auto_delete").GetDiag() + } + + if err = d.Set("created_at", flex.DateTimeToString(clusterNetworkSubnetReservedIP.CreatedAt)); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting created_at: %s", err), "(Data) ibm_is_cluster_network_subnet_reserved_ip", "read", "set-created_at").GetDiag() + } + + if err = d.Set("href", clusterNetworkSubnetReservedIP.Href); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting href: %s", err), "(Data) ibm_is_cluster_network_subnet_reserved_ip", "read", "set-href").GetDiag() + } + + lifecycleReasons := []map[string]interface{}{} + for _, lifecycleReasonsItem := range clusterNetworkSubnetReservedIP.LifecycleReasons { + lifecycleReasonsItemMap, err := DataSourceIBMIsClusterNetworkSubnetReservedIPClusterNetworkSubnetReservedIPLifecycleReasonToMap(&lifecycleReasonsItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_subnet_reserved_ip", "read", "lifecycle_reasons-to-map").GetDiag() + } + lifecycleReasons = append(lifecycleReasons, lifecycleReasonsItemMap) + } + if err = d.Set("lifecycle_reasons", lifecycleReasons); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting lifecycle_reasons: %s", err), "(Data) ibm_is_cluster_network_subnet_reserved_ip", "read", "set-lifecycle_reasons").GetDiag() + } + + if err = d.Set("lifecycle_state", clusterNetworkSubnetReservedIP.LifecycleState); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting lifecycle_state: %s", err), "(Data) ibm_is_cluster_network_subnet_reserved_ip", "read", "set-lifecycle_state").GetDiag() + } + + if err = d.Set("name", clusterNetworkSubnetReservedIP.Name); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting name: %s", err), "(Data) ibm_is_cluster_network_subnet_reserved_ip", "read", "set-name").GetDiag() + } + + if err = d.Set("owner", clusterNetworkSubnetReservedIP.Owner); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting owner: %s", err), "(Data) ibm_is_cluster_network_subnet_reserved_ip", "read", "set-owner").GetDiag() + } + + if err = d.Set("resource_type", clusterNetworkSubnetReservedIP.ResourceType); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting resource_type: %s", err), "(Data) ibm_is_cluster_network_subnet_reserved_ip", "read", "set-resource_type").GetDiag() + } + + if !core.IsNil(clusterNetworkSubnetReservedIP.Target) { + target := []map[string]interface{}{} + targetMap, err := DataSourceIBMIsClusterNetworkSubnetReservedIPClusterNetworkSubnetReservedIPTargetToMap(clusterNetworkSubnetReservedIP.Target) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_subnet_reserved_ip", "read", "target-to-map").GetDiag() + } + target = append(target, targetMap) + if err = d.Set("target", target); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting target: %s", err), "(Data) ibm_is_cluster_network_subnet_reserved_ip", "read", "set-target").GetDiag() + } + } + + return nil +} + +func DataSourceIBMIsClusterNetworkSubnetReservedIPClusterNetworkSubnetReservedIPLifecycleReasonToMap(model *vpcv1.ClusterNetworkSubnetReservedIPLifecycleReason) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["code"] = *model.Code + modelMap["message"] = *model.Message + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkSubnetReservedIPClusterNetworkSubnetReservedIPTargetToMap(model vpcv1.ClusterNetworkSubnetReservedIPTargetIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.ClusterNetworkSubnetReservedIPTargetClusterNetworkInterfaceReferenceClusterNetworkSubnetReservedIPTargetContext); ok { + return DataSourceIBMIsClusterNetworkSubnetReservedIPClusterNetworkSubnetReservedIPTargetClusterNetworkInterfaceReferenceClusterNetworkSubnetReservedIPTargetContextToMap(model.(*vpcv1.ClusterNetworkSubnetReservedIPTargetClusterNetworkInterfaceReferenceClusterNetworkSubnetReservedIPTargetContext)) + } else if _, ok := model.(*vpcv1.ClusterNetworkSubnetReservedIPTarget); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.ClusterNetworkSubnetReservedIPTarget) + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsClusterNetworkSubnetReservedIPDeletedToMap(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.ResourceType != nil { + modelMap["resource_type"] = *model.ResourceType + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.ClusterNetworkSubnetReservedIPTargetIntf subtype encountered") + } +} + +func DataSourceIBMIsClusterNetworkSubnetReservedIPDeletedToMap(model *vpcv1.Deleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = *model.MoreInfo + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkSubnetReservedIPClusterNetworkSubnetReservedIPTargetClusterNetworkInterfaceReferenceClusterNetworkSubnetReservedIPTargetContextToMap(model *vpcv1.ClusterNetworkSubnetReservedIPTargetClusterNetworkInterfaceReferenceClusterNetworkSubnetReservedIPTargetContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsClusterNetworkSubnetReservedIPDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_cluster_network_subnet_reserved_ip_test.go b/ibm/service/vpc/data_source_ibm_is_cluster_network_subnet_reserved_ip_test.go new file mode 100644 index 0000000000..bbeb647db1 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_cluster_network_subnet_reserved_ip_test.go @@ -0,0 +1,207 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_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" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/vpc" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/stretchr/testify/assert" +) + +func TestAccIBMIsClusterNetworkSubnetReservedIPDataSourceBasic(t *testing.T) { + clusterNetworkSubnetReservedIPClusterNetworkID := fmt.Sprintf("tf_cluster_network_id_%d", acctest.RandIntRange(10, 100)) + clusterNetworkSubnetReservedIPClusterNetworkSubnetID := fmt.Sprintf("tf_cluster_network_subnet_id_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsClusterNetworkSubnetReservedIPDataSourceConfigBasic(clusterNetworkSubnetReservedIPClusterNetworkID, clusterNetworkSubnetReservedIPClusterNetworkSubnetID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "cluster_network_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "cluster_network_subnet_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "cluster_network_subnet_reserved_ip_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "address"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "auto_delete"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "lifecycle_reasons.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "owner"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "resource_type"), + ), + }, + }, + }) +} + +func TestAccIBMIsClusterNetworkSubnetReservedIPDataSourceAllArgs(t *testing.T) { + clusterNetworkSubnetReservedIPClusterNetworkID := fmt.Sprintf("tf_cluster_network_id_%d", acctest.RandIntRange(10, 100)) + clusterNetworkSubnetReservedIPClusterNetworkSubnetID := fmt.Sprintf("tf_cluster_network_subnet_id_%d", acctest.RandIntRange(10, 100)) + clusterNetworkSubnetReservedIPAddress := fmt.Sprintf("tf_address_%d", acctest.RandIntRange(10, 100)) + clusterNetworkSubnetReservedIPName := fmt.Sprintf("tf_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: testAccCheckIBMIsClusterNetworkSubnetReservedIPDataSourceConfig(clusterNetworkSubnetReservedIPClusterNetworkID, clusterNetworkSubnetReservedIPClusterNetworkSubnetID, clusterNetworkSubnetReservedIPAddress, clusterNetworkSubnetReservedIPName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "cluster_network_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "cluster_network_subnet_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "cluster_network_subnet_reserved_ip_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "address"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "auto_delete"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "lifecycle_reasons.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "lifecycle_reasons.0.code"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "lifecycle_reasons.0.message"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "lifecycle_reasons.0.more_info"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "owner"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "target.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsClusterNetworkSubnetReservedIPDataSourceConfigBasic(clusterNetworkSubnetReservedIPClusterNetworkID string, clusterNetworkSubnetReservedIPClusterNetworkSubnetID string) string { + return fmt.Sprintf(` + data "ibm_is_cluster_network_subnet_reserved_ip" "is_cluster_network_subnet_reserved_ip_instance" { + cluster_network_id = "02c7-10274052-f495-4920-a67f-870eb3b87003" + cluster_network_subnet_id = "02c7-27ca8206-f73b-4d8f-b996-913711b98ff0" + cluster_network_subnet_reserved_ip_id = "02c7-111099cc-39e2-4c2f-9a32-109bb5a2ae7e" + } + `) +} + +func testAccCheckIBMIsClusterNetworkSubnetReservedIPDataSourceConfig(clusterNetworkSubnetReservedIPClusterNetworkID string, clusterNetworkSubnetReservedIPClusterNetworkSubnetID string, clusterNetworkSubnetReservedIPAddress string, clusterNetworkSubnetReservedIPName string) string { + return fmt.Sprintf(` + resource "ibm_is_cluster_network_subnet_reserved_ip" "is_cluster_network_subnet_reserved_ip_instance" { + cluster_network_id = "%s" + cluster_network_subnet_id = "%s" + address = "%s" + name = "%s" + } + + data "ibm_is_cluster_network_subnet_reserved_ip" "is_cluster_network_subnet_reserved_ip_instance" { + cluster_network_id = ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance.cluster_network_id + cluster_network_subnet_id = ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance.cluster_network_subnet_id + cluster_network_subnet_reserved_ip_id = ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance.cluster_network_subnet_reserved_ip_id + } + `, clusterNetworkSubnetReservedIPClusterNetworkID, clusterNetworkSubnetReservedIPClusterNetworkSubnetID, clusterNetworkSubnetReservedIPAddress, clusterNetworkSubnetReservedIPName) +} + +func TestDataSourceIBMIsClusterNetworkSubnetReservedIPClusterNetworkSubnetReservedIPLifecycleReasonToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["code"] = "resource_suspended_by_provider" + model["message"] = "The resource has been suspended. Contact IBM support with the CRN for next steps." + model["more_info"] = "https://cloud.ibm.com/apidocs/vpc#resource-suspension" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ClusterNetworkSubnetReservedIPLifecycleReason) + model.Code = core.StringPtr("resource_suspended_by_provider") + model.Message = core.StringPtr("The resource has been suspended. Contact IBM support with the CRN for next steps.") + model.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#resource-suspension") + + result, err := vpc.DataSourceIBMIsClusterNetworkSubnetReservedIPClusterNetworkSubnetReservedIPLifecycleReasonToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkSubnetReservedIPClusterNetworkSubnetReservedIPTargetToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + deletedModel := make(map[string]interface{}) + deletedModel["more_info"] = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + + model := make(map[string]interface{}) + model["deleted"] = []map[string]interface{}{deletedModel} + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/interfaces/0717-ffc092f7-5d02-4b93-ab69-26860529b9fb" + model["id"] = "0717-ffc092f7-5d02-4b93-ab69-26860529b9fb" + model["name"] = "my-cluster-network-interface" + model["resource_type"] = "cluster_network_interface" + + assert.Equal(t, result, model) + } + + deletedModel := new(vpcv1.Deleted) + deletedModel.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#deleted-resources") + + model := new(vpcv1.ClusterNetworkSubnetReservedIPTarget) + model.Deleted = deletedModel + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/interfaces/0717-ffc092f7-5d02-4b93-ab69-26860529b9fb") + model.ID = core.StringPtr("0717-ffc092f7-5d02-4b93-ab69-26860529b9fb") + model.Name = core.StringPtr("my-cluster-network-interface") + model.ResourceType = core.StringPtr("cluster_network_interface") + + result, err := vpc.DataSourceIBMIsClusterNetworkSubnetReservedIPClusterNetworkSubnetReservedIPTargetToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkSubnetReservedIPDeletedToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["more_info"] = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.Deleted) + model.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#deleted-resources") + + result, err := vpc.DataSourceIBMIsClusterNetworkSubnetReservedIPDeletedToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkSubnetReservedIPClusterNetworkSubnetReservedIPTargetClusterNetworkInterfaceReferenceClusterNetworkSubnetReservedIPTargetContextToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + deletedModel := make(map[string]interface{}) + deletedModel["more_info"] = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + + model := make(map[string]interface{}) + model["deleted"] = []map[string]interface{}{deletedModel} + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/interfaces/0717-ffc092f7-5d02-4b93-ab69-26860529b9fb" + model["id"] = "0717-ffc092f7-5d02-4b93-ab69-26860529b9fb" + model["name"] = "my-cluster-network-interface" + model["resource_type"] = "cluster_network_interface" + + assert.Equal(t, result, model) + } + + deletedModel := new(vpcv1.Deleted) + deletedModel.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#deleted-resources") + + model := new(vpcv1.ClusterNetworkSubnetReservedIPTargetClusterNetworkInterfaceReferenceClusterNetworkSubnetReservedIPTargetContext) + model.Deleted = deletedModel + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/interfaces/0717-ffc092f7-5d02-4b93-ab69-26860529b9fb") + model.ID = core.StringPtr("0717-ffc092f7-5d02-4b93-ab69-26860529b9fb") + model.Name = core.StringPtr("my-cluster-network-interface") + model.ResourceType = core.StringPtr("cluster_network_interface") + + result, err := vpc.DataSourceIBMIsClusterNetworkSubnetReservedIPClusterNetworkSubnetReservedIPTargetClusterNetworkInterfaceReferenceClusterNetworkSubnetReservedIPTargetContextToMap(model) + assert.Nil(t, err) + checkResult(result) +} diff --git a/ibm/service/vpc/data_source_ibm_is_cluster_network_subnet_reserved_ips.go b/ibm/service/vpc/data_source_ibm_is_cluster_network_subnet_reserved_ips.go new file mode 100644 index 0000000000..0d778a5c3d --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_cluster_network_subnet_reserved_ips.go @@ -0,0 +1,319 @@ +// Copyright IBM Corp. 2024 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/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsClusterNetworkSubnetReservedIps() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsClusterNetworkSubnetReservedIpsRead, + + Schema: map[string]*schema.Schema{ + "cluster_network_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The cluster network identifier.", + }, + "cluster_network_subnet_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The cluster network subnet identifier.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Filters the collection to resources with a `name` property matching the exact specified name.", + }, + "sort": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "address", + Description: "Sorts the returned collection by the specified property name in ascending order. A `-` may be prepended to the name to sort in descending order. For example, the value `-created_at` sorts the collection by the `created_at` property in descending order, and the value `name` sorts it by the `name` property in ascending order.", + }, + "reserved_ips": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A page of reserved IPs for the cluster network subnet.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address is pending allocation, the value will be `0.0.0.0`.This property may [expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) to support IPv6 addresses in the future.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this cluster network subnet reserved IP member will be automatically deleted when either `target` is deleted, or the cluster network subnet reserved IP is unbound.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the cluster network subnet reserved IP was created.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network subnet reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network subnet reserved IP.", + }, + "lifecycle_reasons": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current `lifecycle_state` (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the cluster network subnet reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network subnet reserved IP. The name is unique across all reserved IPs in a cluster network subnet.", + }, + "owner": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The owner of the cluster network subnet reserved IPThe enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "target": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The target this cluster network subnet reserved IP is bound to.If absent, this cluster network subnet reserved IP is provider-owned or unbound.", + 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 cluster network interface.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network interface.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network interface. The name is unique across all interfaces in the cluster network.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsClusterNetworkSubnetReservedIpsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_subnet_reserved_ips", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + listClusterNetworkSubnetReservedIpsOptions := &vpcv1.ListClusterNetworkSubnetReservedIpsOptions{} + + listClusterNetworkSubnetReservedIpsOptions.SetClusterNetworkID(d.Get("cluster_network_id").(string)) + listClusterNetworkSubnetReservedIpsOptions.SetClusterNetworkSubnetID(d.Get("cluster_network_subnet_id").(string)) + if _, ok := d.GetOk("name"); ok { + listClusterNetworkSubnetReservedIpsOptions.SetName(d.Get("name").(string)) + } + if _, ok := d.GetOk("sort"); ok { + listClusterNetworkSubnetReservedIpsOptions.SetSort(d.Get("sort").(string)) + } + + var pager *vpcv1.ClusterNetworkSubnetReservedIpsPager + pager, err = vpcClient.NewClusterNetworkSubnetReservedIpsPager(listClusterNetworkSubnetReservedIpsOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_subnet_reserved_ips", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + allItems, err := pager.GetAll() + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("ClusterNetworkSubnetReservedIpsPager.GetAll() failed %s", err), "(Data) ibm_is_cluster_network_subnet_reserved_ips", "read") + log.Printf("[DEBUG] %s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(dataSourceIBMIsClusterNetworkSubnetReservedIpsID(d)) + + mapSlice := []map[string]interface{}{} + for _, modelItem := range allItems { + modelMap, err := DataSourceIBMIsClusterNetworkSubnetReservedIpsClusterNetworkSubnetReservedIPToMap(&modelItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_subnet_reserved_ips", "read", "ClusterNetworks-to-map").GetDiag() + } + mapSlice = append(mapSlice, modelMap) + } + + if err = d.Set("reserved_ips", mapSlice); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting reserved_ips %s", err), "(Data) ibm_is_cluster_network_subnet_reserved_ips", "read", "reserved_ips-set").GetDiag() + } + + return nil +} + +// dataSourceIBMIsClusterNetworkSubnetReservedIpsID returns a reasonable ID for the list. +func dataSourceIBMIsClusterNetworkSubnetReservedIpsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func DataSourceIBMIsClusterNetworkSubnetReservedIpsClusterNetworkSubnetReservedIPToMap(model *vpcv1.ClusterNetworkSubnetReservedIP) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["address"] = *model.Address + modelMap["auto_delete"] = *model.AutoDelete + modelMap["created_at"] = model.CreatedAt.String() + modelMap["href"] = *model.Href + modelMap["id"] = *model.ID + lifecycleReasons := []map[string]interface{}{} + for _, lifecycleReasonsItem := range model.LifecycleReasons { + lifecycleReasonsItemMap, err := DataSourceIBMIsClusterNetworkSubnetReservedIpsClusterNetworkSubnetReservedIPLifecycleReasonToMap(&lifecycleReasonsItem) // #nosec G601 + if err != nil { + return modelMap, err + } + lifecycleReasons = append(lifecycleReasons, lifecycleReasonsItemMap) + } + modelMap["lifecycle_reasons"] = lifecycleReasons + modelMap["lifecycle_state"] = *model.LifecycleState + modelMap["name"] = *model.Name + modelMap["owner"] = *model.Owner + modelMap["resource_type"] = *model.ResourceType + if model.Target != nil { + targetMap, err := DataSourceIBMIsClusterNetworkSubnetReservedIpsClusterNetworkSubnetReservedIPTargetToMap(model.Target) + if err != nil { + return modelMap, err + } + modelMap["target"] = []map[string]interface{}{targetMap} + } + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkSubnetReservedIpsClusterNetworkSubnetReservedIPLifecycleReasonToMap(model *vpcv1.ClusterNetworkSubnetReservedIPLifecycleReason) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["code"] = *model.Code + modelMap["message"] = *model.Message + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkSubnetReservedIpsClusterNetworkSubnetReservedIPTargetToMap(model vpcv1.ClusterNetworkSubnetReservedIPTargetIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.ClusterNetworkSubnetReservedIPTargetClusterNetworkInterfaceReferenceClusterNetworkSubnetReservedIPTargetContext); ok { + return DataSourceIBMIsClusterNetworkSubnetReservedIpsClusterNetworkSubnetReservedIPTargetClusterNetworkInterfaceReferenceClusterNetworkSubnetReservedIPTargetContextToMap(model.(*vpcv1.ClusterNetworkSubnetReservedIPTargetClusterNetworkInterfaceReferenceClusterNetworkSubnetReservedIPTargetContext)) + } else if _, ok := model.(*vpcv1.ClusterNetworkSubnetReservedIPTarget); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.ClusterNetworkSubnetReservedIPTarget) + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsClusterNetworkSubnetReservedIpsDeletedToMap(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.ResourceType != nil { + modelMap["resource_type"] = *model.ResourceType + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.ClusterNetworkSubnetReservedIPTargetIntf subtype encountered") + } +} + +func DataSourceIBMIsClusterNetworkSubnetReservedIpsDeletedToMap(model *vpcv1.Deleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = *model.MoreInfo + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkSubnetReservedIpsClusterNetworkSubnetReservedIPTargetClusterNetworkInterfaceReferenceClusterNetworkSubnetReservedIPTargetContextToMap(model *vpcv1.ClusterNetworkSubnetReservedIPTargetClusterNetworkInterfaceReferenceClusterNetworkSubnetReservedIPTargetContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsClusterNetworkSubnetReservedIpsDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_cluster_network_subnet_reserved_ips_test.go b/ibm/service/vpc/data_source_ibm_is_cluster_network_subnet_reserved_ips_test.go new file mode 100644 index 0000000000..b41667ff5e --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_cluster_network_subnet_reserved_ips_test.go @@ -0,0 +1,274 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_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" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/vpc" + . "github.com/IBM-Cloud/terraform-provider-ibm/ibm/unittest" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/stretchr/testify/assert" +) + +func TestAccIBMIsClusterNetworkSubnetReservedIpsDataSourceBasic(t *testing.T) { + clusterNetworkSubnetReservedIPClusterNetworkID := fmt.Sprintf("tf_cluster_network_id_%d", acctest.RandIntRange(10, 100)) + clusterNetworkSubnetReservedIPClusterNetworkSubnetID := fmt.Sprintf("tf_cluster_network_subnet_id_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsClusterNetworkSubnetReservedIpsDataSourceConfigBasic(clusterNetworkSubnetReservedIPClusterNetworkID, clusterNetworkSubnetReservedIPClusterNetworkSubnetID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "cluster_network_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "cluster_network_subnet_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "reserved_ips.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "reserved_ips.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "reserved_ips.0.address"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "reserved_ips.0.auto_delete"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "reserved_ips.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "reserved_ips.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "reserved_ips.0.lifecycle_reasons.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "reserved_ips.0.lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "reserved_ips.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "reserved_ips.0.owner"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "reserved_ips.0.resource_type"), + ), + }, + }, + }) +} + +func TestAccIBMIsClusterNetworkSubnetReservedIpsDataSourceAllArgs(t *testing.T) { + clusterNetworkSubnetReservedIPClusterNetworkID := fmt.Sprintf("tf_cluster_network_id_%d", acctest.RandIntRange(10, 100)) + clusterNetworkSubnetReservedIPClusterNetworkSubnetID := fmt.Sprintf("tf_cluster_network_subnet_id_%d", acctest.RandIntRange(10, 100)) + clusterNetworkSubnetReservedIPAddress := fmt.Sprintf("tf_address_%d", acctest.RandIntRange(10, 100)) + clusterNetworkSubnetReservedIPName := fmt.Sprintf("tf_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: testAccCheckIBMIsClusterNetworkSubnetReservedIpsDataSourceConfig(clusterNetworkSubnetReservedIPClusterNetworkID, clusterNetworkSubnetReservedIPClusterNetworkSubnetID, clusterNetworkSubnetReservedIPAddress, clusterNetworkSubnetReservedIPName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "cluster_network_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "cluster_network_subnet_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "sort"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "reserved_ips.#"), + resource.TestCheckResourceAttr("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "reserved_ips.0.address", clusterNetworkSubnetReservedIPAddress), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "reserved_ips.0.auto_delete"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "reserved_ips.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "reserved_ips.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "reserved_ips.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "reserved_ips.0.lifecycle_state"), + resource.TestCheckResourceAttr("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "reserved_ips.0.name", clusterNetworkSubnetReservedIPName), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "reserved_ips.0.owner"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet_reserved_ips.is_cluster_network_subnet_reserved_ips_instance", "reserved_ips.0.resource_type"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsClusterNetworkSubnetReservedIpsDataSourceConfigBasic(clusterNetworkSubnetReservedIPClusterNetworkID string, clusterNetworkSubnetReservedIPClusterNetworkSubnetID string) string { + return fmt.Sprintf(` + + data "ibm_is_cluster_network_subnet_reserved_ips" "is_cluster_network_subnet_reserved_ips_instance" { + cluster_network_id = "02c7-10274052-f495-4920-a67f-870eb3b87003" + cluster_network_subnet_id = "02c7-27ca8206-f73b-4d8f-b996-913711b98ff0" + } + `) +} + +func testAccCheckIBMIsClusterNetworkSubnetReservedIpsDataSourceConfig(clusterNetworkSubnetReservedIPClusterNetworkID string, clusterNetworkSubnetReservedIPClusterNetworkSubnetID string, clusterNetworkSubnetReservedIPAddress string, clusterNetworkSubnetReservedIPName string) string { + return fmt.Sprintf(` + resource "ibm_is_cluster_network_subnet_reserved_ip" "is_cluster_network_subnet_reserved_ip_instance" { + cluster_network_id = "%s" + cluster_network_subnet_id = "%s" + address = "%s" + name = "%s" + } + + data "ibm_is_cluster_network_subnet_reserved_ips" "is_cluster_network_subnet_reserved_ips_instance" { + cluster_network_id = ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance.cluster_network_id + cluster_network_subnet_id = ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance.cluster_network_subnet_id + name = ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance.name + sort = "name" + } + `, clusterNetworkSubnetReservedIPClusterNetworkID, clusterNetworkSubnetReservedIPClusterNetworkSubnetID, clusterNetworkSubnetReservedIPAddress, clusterNetworkSubnetReservedIPName) +} + +func TestDataSourceIBMIsClusterNetworkSubnetReservedIpsClusterNetworkSubnetReservedIPToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + clusterNetworkSubnetReservedIPLifecycleReasonModel := make(map[string]interface{}) + clusterNetworkSubnetReservedIPLifecycleReasonModel["code"] = "resource_suspended_by_provider" + clusterNetworkSubnetReservedIPLifecycleReasonModel["message"] = "The resource has been suspended. Contact IBM support with the CRN for next steps." + clusterNetworkSubnetReservedIPLifecycleReasonModel["more_info"] = "https://cloud.ibm.com/apidocs/vpc#resource-suspension" + + deletedModel := make(map[string]interface{}) + deletedModel["more_info"] = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + + clusterNetworkSubnetReservedIPTargetModel := make(map[string]interface{}) + clusterNetworkSubnetReservedIPTargetModel["deleted"] = []map[string]interface{}{deletedModel} + clusterNetworkSubnetReservedIPTargetModel["href"] = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/interfaces/0717-ffc092f7-5d02-4b93-ab69-26860529b9fb" + clusterNetworkSubnetReservedIPTargetModel["id"] = "0717-ffc092f7-5d02-4b93-ab69-26860529b9fb" + clusterNetworkSubnetReservedIPTargetModel["name"] = "my-cluster-network-interface" + clusterNetworkSubnetReservedIPTargetModel["resource_type"] = "cluster_network_interface" + + model := make(map[string]interface{}) + model["address"] = "10.1.0.6" + model["auto_delete"] = false + model["created_at"] = "2019-01-01T12:00:00.000Z" + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930/reserved_ips/6d353a0f-aeb1-4ae1-832e-1110d10981bb" + model["id"] = "6d353a0f-aeb1-4ae1-832e-1110d10981bb" + model["lifecycle_reasons"] = []map[string]interface{}{clusterNetworkSubnetReservedIPLifecycleReasonModel} + model["lifecycle_state"] = "stable" + model["name"] = "my-cluster-network-subnet-reserved-ip" + model["owner"] = "user" + model["resource_type"] = "cluster_network_subnet_reserved_ip" + model["target"] = []map[string]interface{}{clusterNetworkSubnetReservedIPTargetModel} + + assert.Equal(t, result, model) + } + + clusterNetworkSubnetReservedIPLifecycleReasonModel := new(vpcv1.ClusterNetworkSubnetReservedIPLifecycleReason) + clusterNetworkSubnetReservedIPLifecycleReasonModel.Code = core.StringPtr("resource_suspended_by_provider") + clusterNetworkSubnetReservedIPLifecycleReasonModel.Message = core.StringPtr("The resource has been suspended. Contact IBM support with the CRN for next steps.") + clusterNetworkSubnetReservedIPLifecycleReasonModel.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#resource-suspension") + + deletedModel := new(vpcv1.Deleted) + deletedModel.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#deleted-resources") + + clusterNetworkSubnetReservedIPTargetModel := new(vpcv1.ClusterNetworkSubnetReservedIPTargetClusterNetworkInterfaceReferenceClusterNetworkSubnetReservedIPTargetContext) + clusterNetworkSubnetReservedIPTargetModel.Deleted = deletedModel + clusterNetworkSubnetReservedIPTargetModel.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/interfaces/0717-ffc092f7-5d02-4b93-ab69-26860529b9fb") + clusterNetworkSubnetReservedIPTargetModel.ID = core.StringPtr("0717-ffc092f7-5d02-4b93-ab69-26860529b9fb") + clusterNetworkSubnetReservedIPTargetModel.Name = core.StringPtr("my-cluster-network-interface") + clusterNetworkSubnetReservedIPTargetModel.ResourceType = core.StringPtr("cluster_network_interface") + + model := new(vpcv1.ClusterNetworkSubnetReservedIP) + model.Address = core.StringPtr("10.1.0.6") + model.AutoDelete = core.BoolPtr(false) + model.CreatedAt = CreateMockDateTime("2019-01-01T12:00:00.000Z") + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930/reserved_ips/6d353a0f-aeb1-4ae1-832e-1110d10981bb") + model.ID = core.StringPtr("6d353a0f-aeb1-4ae1-832e-1110d10981bb") + model.LifecycleReasons = []vpcv1.ClusterNetworkSubnetReservedIPLifecycleReason{*clusterNetworkSubnetReservedIPLifecycleReasonModel} + model.LifecycleState = core.StringPtr("stable") + model.Name = core.StringPtr("my-cluster-network-subnet-reserved-ip") + model.Owner = core.StringPtr("user") + model.ResourceType = core.StringPtr("cluster_network_subnet_reserved_ip") + model.Target = clusterNetworkSubnetReservedIPTargetModel + + result, err := vpc.DataSourceIBMIsClusterNetworkSubnetReservedIpsClusterNetworkSubnetReservedIPToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkSubnetReservedIpsClusterNetworkSubnetReservedIPLifecycleReasonToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["code"] = "resource_suspended_by_provider" + model["message"] = "The resource has been suspended. Contact IBM support with the CRN for next steps." + model["more_info"] = "https://cloud.ibm.com/apidocs/vpc#resource-suspension" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ClusterNetworkSubnetReservedIPLifecycleReason) + model.Code = core.StringPtr("resource_suspended_by_provider") + model.Message = core.StringPtr("The resource has been suspended. Contact IBM support with the CRN for next steps.") + model.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#resource-suspension") + + result, err := vpc.DataSourceIBMIsClusterNetworkSubnetReservedIpsClusterNetworkSubnetReservedIPLifecycleReasonToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkSubnetReservedIpsClusterNetworkSubnetReservedIPTargetToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + deletedModel := make(map[string]interface{}) + deletedModel["more_info"] = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + + model := make(map[string]interface{}) + model["deleted"] = []map[string]interface{}{deletedModel} + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/interfaces/0717-ffc092f7-5d02-4b93-ab69-26860529b9fb" + model["id"] = "0717-ffc092f7-5d02-4b93-ab69-26860529b9fb" + model["name"] = "my-cluster-network-interface" + model["resource_type"] = "cluster_network_interface" + + assert.Equal(t, result, model) + } + + deletedModel := new(vpcv1.Deleted) + deletedModel.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#deleted-resources") + + model := new(vpcv1.ClusterNetworkSubnetReservedIPTarget) + model.Deleted = deletedModel + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/interfaces/0717-ffc092f7-5d02-4b93-ab69-26860529b9fb") + model.ID = core.StringPtr("0717-ffc092f7-5d02-4b93-ab69-26860529b9fb") + model.Name = core.StringPtr("my-cluster-network-interface") + model.ResourceType = core.StringPtr("cluster_network_interface") + + result, err := vpc.DataSourceIBMIsClusterNetworkSubnetReservedIpsClusterNetworkSubnetReservedIPTargetToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkSubnetReservedIpsDeletedToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["more_info"] = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.Deleted) + model.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#deleted-resources") + + result, err := vpc.DataSourceIBMIsClusterNetworkSubnetReservedIpsDeletedToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkSubnetReservedIpsClusterNetworkSubnetReservedIPTargetClusterNetworkInterfaceReferenceClusterNetworkSubnetReservedIPTargetContextToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + deletedModel := make(map[string]interface{}) + deletedModel["more_info"] = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + + model := make(map[string]interface{}) + model["deleted"] = []map[string]interface{}{deletedModel} + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/interfaces/0717-ffc092f7-5d02-4b93-ab69-26860529b9fb" + model["id"] = "0717-ffc092f7-5d02-4b93-ab69-26860529b9fb" + model["name"] = "my-cluster-network-interface" + model["resource_type"] = "cluster_network_interface" + + assert.Equal(t, result, model) + } + + deletedModel := new(vpcv1.Deleted) + deletedModel.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#deleted-resources") + + model := new(vpcv1.ClusterNetworkSubnetReservedIPTargetClusterNetworkInterfaceReferenceClusterNetworkSubnetReservedIPTargetContext) + model.Deleted = deletedModel + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/interfaces/0717-ffc092f7-5d02-4b93-ab69-26860529b9fb") + model.ID = core.StringPtr("0717-ffc092f7-5d02-4b93-ab69-26860529b9fb") + model.Name = core.StringPtr("my-cluster-network-interface") + model.ResourceType = core.StringPtr("cluster_network_interface") + + result, err := vpc.DataSourceIBMIsClusterNetworkSubnetReservedIpsClusterNetworkSubnetReservedIPTargetClusterNetworkInterfaceReferenceClusterNetworkSubnetReservedIPTargetContextToMap(model) + assert.Nil(t, err) + checkResult(result) +} diff --git a/ibm/service/vpc/data_source_ibm_is_cluster_network_subnet_test.go b/ibm/service/vpc/data_source_ibm_is_cluster_network_subnet_test.go new file mode 100644 index 0000000000..471f984d7d --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_cluster_network_subnet_test.go @@ -0,0 +1,130 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_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" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/vpc" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/stretchr/testify/assert" +) + +func TestAccIBMIsClusterNetworkSubnetDataSourceBasic(t *testing.T) { + clusterNetworkSubnetClusterNetworkID := fmt.Sprintf("tf_cluster_network_id_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsClusterNetworkSubnetDataSourceConfigBasic(clusterNetworkSubnetClusterNetworkID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "cluster_network_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "cluster_network_subnet_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "available_ipv4_address_count"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "ip_version"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "ipv4_cidr_block"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "lifecycle_reasons.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "total_ipv4_address_count"), + ), + }, + }, + }) +} + +func TestAccIBMIsClusterNetworkSubnetDataSourceAllArgs(t *testing.T) { + clusterNetworkSubnetClusterNetworkID := fmt.Sprintf("tf_cluster_network_id_%d", acctest.RandIntRange(10, 100)) + clusterNetworkSubnetIPVersion := "ipv4" + clusterNetworkSubnetIpv4CIDRBlock := fmt.Sprintf("tf_ipv4_cidr_block_%d", acctest.RandIntRange(10, 100)) + clusterNetworkSubnetName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + clusterNetworkSubnetTotalIpv4AddressCount := fmt.Sprintf("%d", acctest.RandIntRange(8, 16777216)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsClusterNetworkSubnetDataSourceConfig(clusterNetworkSubnetClusterNetworkID, clusterNetworkSubnetIPVersion, clusterNetworkSubnetIpv4CIDRBlock, clusterNetworkSubnetName, clusterNetworkSubnetTotalIpv4AddressCount), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "cluster_network_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "cluster_network_subnet_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "available_ipv4_address_count"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "ip_version"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "ipv4_cidr_block"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "lifecycle_reasons.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "lifecycle_reasons.0.code"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "lifecycle_reasons.0.message"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "lifecycle_reasons.0.more_info"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "total_ipv4_address_count"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsClusterNetworkSubnetDataSourceConfigBasic(clusterNetworkSubnetClusterNetworkID string) string { + return fmt.Sprintf(` + + data "ibm_is_cluster_network_subnet" "is_cluster_network_subnet_instance" { + cluster_network_id = "02c7-10274052-f495-4920-a67f-870eb3b87003" + cluster_network_subnet_id = "02c7-27ca8206-f73b-4d8f-b996-913711b98ff0" + } + `) +} + +func testAccCheckIBMIsClusterNetworkSubnetDataSourceConfig(clusterNetworkSubnetClusterNetworkID string, clusterNetworkSubnetIPVersion string, clusterNetworkSubnetIpv4CIDRBlock string, clusterNetworkSubnetName string, clusterNetworkSubnetTotalIpv4AddressCount string) string { + return fmt.Sprintf(` + resource "ibm_is_cluster_network_subnet" "is_cluster_network_subnet_instance" { + cluster_network_id = "%s" + ip_version = "%s" + ipv4_cidr_block = "%s" + name = "%s" + total_ipv4_address_count = %s + } + + data "ibm_is_cluster_network_subnet" "is_cluster_network_subnet_instance" { + cluster_network_id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_id + cluster_network_subnet_id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + `, clusterNetworkSubnetClusterNetworkID, clusterNetworkSubnetIPVersion, clusterNetworkSubnetIpv4CIDRBlock, clusterNetworkSubnetName, clusterNetworkSubnetTotalIpv4AddressCount) +} + +func TestDataSourceIBMIsClusterNetworkSubnetClusterNetworkSubnetLifecycleReasonToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["code"] = "resource_suspended_by_provider" + model["message"] = "The resource has been suspended. Contact IBM support with the CRN for next steps." + model["more_info"] = "https://cloud.ibm.com/apidocs/vpc#resource-suspension" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ClusterNetworkSubnetLifecycleReason) + model.Code = core.StringPtr("resource_suspended_by_provider") + model.Message = core.StringPtr("The resource has been suspended. Contact IBM support with the CRN for next steps.") + model.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#resource-suspension") + + result, err := vpc.DataSourceIBMIsClusterNetworkSubnetClusterNetworkSubnetLifecycleReasonToMap(model) + assert.Nil(t, err) + checkResult(result) +} diff --git a/ibm/service/vpc/data_source_ibm_is_cluster_network_subnets.go b/ibm/service/vpc/data_source_ibm_is_cluster_network_subnets.go new file mode 100644 index 0000000000..7922db0149 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_cluster_network_subnets.go @@ -0,0 +1,216 @@ +// Copyright IBM Corp. 2024 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/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsClusterNetworkSubnets() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsClusterNetworkSubnetsRead, + + Schema: map[string]*schema.Schema{ + "cluster_network_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The cluster network identifier.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Filters the collection to resources with a `name` property matching the exact specified name.", + }, + "sort": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "-created_at", + Description: "Sorts the returned collection by the specified property name in ascending order. A `-` may be prepended to the name to sort in descending order. For example, the value `-created_at` sorts the collection by the `created_at` property in descending order, and the value `name` sorts it by the `name` property in ascending order.", + }, + "subnets": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A page of subnets for the cluster network.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "available_ipv4_address_count": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The number of IPv4 addresses in this cluster network subnet that are not in use, and have not been reserved by the user or the provider.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the cluster network subnet was created.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network subnet.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network subnet.", + }, + "ip_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP version for this cluster network subnet.The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "ipv4_cidr_block": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IPv4 range of this cluster network subnet, expressed in CIDR format.", + }, + "lifecycle_reasons": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current `lifecycle_state` (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the cluster network subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network subnet. The name is unique across all cluster network subnets in the cluster network.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "total_ipv4_address_count": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The total number of IPv4 addresses in this cluster network subnet.Note: This is calculated as 2(32 - prefix length). For example, the prefix length `/24` gives:
2(32 - 24) = 28 = 256 addresses.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsClusterNetworkSubnetsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_subnets", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + listClusterNetworkSubnetsOptions := &vpcv1.ListClusterNetworkSubnetsOptions{} + + listClusterNetworkSubnetsOptions.SetClusterNetworkID(d.Get("cluster_network_id").(string)) + if _, ok := d.GetOk("name"); ok { + listClusterNetworkSubnetsOptions.SetName(d.Get("name").(string)) + } + if _, ok := d.GetOk("sort"); ok { + listClusterNetworkSubnetsOptions.SetSort(d.Get("sort").(string)) + } + + var pager *vpcv1.ClusterNetworkSubnetsPager + pager, err = vpcClient.NewClusterNetworkSubnetsPager(listClusterNetworkSubnetsOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_subnets", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + allItems, err := pager.GetAll() + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("ClusterNetworkSubnetsPager.GetAll() failed %s", err), "(Data) ibm_is_cluster_network_subnets", "read") + log.Printf("[DEBUG] %s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(dataSourceIBMIsClusterNetworkSubnetsID(d)) + + mapSlice := []map[string]interface{}{} + for _, modelItem := range allItems { + modelMap, err := DataSourceIBMIsClusterNetworkSubnetsClusterNetworkSubnetToMap(&modelItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_network_subnets", "read", "ClusterNetworks-to-map").GetDiag() + } + mapSlice = append(mapSlice, modelMap) + } + + if err = d.Set("subnets", mapSlice); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting subnets %s", err), "(Data) ibm_is_cluster_network_subnets", "read", "subnets-set").GetDiag() + } + + return nil +} + +// dataSourceIBMIsClusterNetworkSubnetsID returns a reasonable ID for the list. +func dataSourceIBMIsClusterNetworkSubnetsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func DataSourceIBMIsClusterNetworkSubnetsClusterNetworkSubnetToMap(model *vpcv1.ClusterNetworkSubnet) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["available_ipv4_address_count"] = flex.IntValue(model.AvailableIpv4AddressCount) + modelMap["created_at"] = model.CreatedAt.String() + modelMap["href"] = *model.Href + modelMap["id"] = *model.ID + modelMap["ip_version"] = *model.IPVersion + modelMap["ipv4_cidr_block"] = *model.Ipv4CIDRBlock + lifecycleReasons := []map[string]interface{}{} + for _, lifecycleReasonsItem := range model.LifecycleReasons { + lifecycleReasonsItemMap, err := DataSourceIBMIsClusterNetworkSubnetsClusterNetworkSubnetLifecycleReasonToMap(&lifecycleReasonsItem) // #nosec G601 + if err != nil { + return modelMap, err + } + lifecycleReasons = append(lifecycleReasons, lifecycleReasonsItemMap) + } + modelMap["lifecycle_reasons"] = lifecycleReasons + modelMap["lifecycle_state"] = *model.LifecycleState + modelMap["name"] = *model.Name + modelMap["resource_type"] = *model.ResourceType + modelMap["total_ipv4_address_count"] = flex.IntValue(model.TotalIpv4AddressCount) + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworkSubnetsClusterNetworkSubnetLifecycleReasonToMap(model *vpcv1.ClusterNetworkSubnetLifecycleReason) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["code"] = *model.Code + modelMap["message"] = *model.Message + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_cluster_network_subnets_test.go b/ibm/service/vpc/data_source_ibm_is_cluster_network_subnets_test.go new file mode 100644 index 0000000000..d58a0917bb --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_cluster_network_subnets_test.go @@ -0,0 +1,177 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_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" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/vpc" + . "github.com/IBM-Cloud/terraform-provider-ibm/ibm/unittest" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/stretchr/testify/assert" +) + +func TestAccIBMIsClusterNetworkSubnetsDataSourceBasic(t *testing.T) { + clusterNetworkSubnetClusterNetworkID := fmt.Sprintf("tf_cluster_network_id_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsClusterNetworkSubnetsDataSourceConfigBasic(clusterNetworkSubnetClusterNetworkID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "cluster_network_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.0.available_ipv4_address_count"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.0.ip_version"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.0.ipv4_cidr_block"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.0.lifecycle_reasons.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.0.lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.0.total_ipv4_address_count"), + ), + }, + }, + }) +} + +func TestAccIBMIsClusterNetworkSubnetsDataSourceAllArgs(t *testing.T) { + clusterNetworkSubnetClusterNetworkID := fmt.Sprintf("tf_cluster_network_id_%d", acctest.RandIntRange(10, 100)) + clusterNetworkSubnetIPVersion := "ipv4" + clusterNetworkSubnetIpv4CIDRBlock := fmt.Sprintf("tf_ipv4_cidr_block_%d", acctest.RandIntRange(10, 100)) + clusterNetworkSubnetName := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + clusterNetworkSubnetTotalIpv4AddressCount := fmt.Sprintf("%d", acctest.RandIntRange(8, 16777216)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsClusterNetworkSubnetsDataSourceConfig(clusterNetworkSubnetClusterNetworkID, clusterNetworkSubnetIPVersion, clusterNetworkSubnetIpv4CIDRBlock, clusterNetworkSubnetName, clusterNetworkSubnetTotalIpv4AddressCount), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "cluster_network_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "sort"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.0.available_ipv4_address_count"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.0.id"), + resource.TestCheckResourceAttr("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.0.ip_version", clusterNetworkSubnetIPVersion), + resource.TestCheckResourceAttr("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.0.ipv4_cidr_block", clusterNetworkSubnetIpv4CIDRBlock), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.0.lifecycle_state"), + resource.TestCheckResourceAttr("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.0.name", clusterNetworkSubnetName), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.0.resource_type"), + resource.TestCheckResourceAttr("data.ibm_is_cluster_network_subnets.is_cluster_network_subnets_instance", "subnets.0.total_ipv4_address_count", clusterNetworkSubnetTotalIpv4AddressCount), + ), + }, + }, + }) +} + +func testAccCheckIBMIsClusterNetworkSubnetsDataSourceConfigBasic(clusterNetworkSubnetClusterNetworkID string) string { + return fmt.Sprintf(` + + data "ibm_is_cluster_network_subnets" "is_cluster_network_subnets_instance" { + cluster_network_id = "02c7-10274052-f495-4920-a67f-870eb3b87003" + } + `) +} + +func testAccCheckIBMIsClusterNetworkSubnetsDataSourceConfig(clusterNetworkSubnetClusterNetworkID string, clusterNetworkSubnetIPVersion string, clusterNetworkSubnetIpv4CIDRBlock string, clusterNetworkSubnetName string, clusterNetworkSubnetTotalIpv4AddressCount string) string { + return fmt.Sprintf(` + resource "ibm_is_cluster_network_subnet" "is_cluster_network_subnet_instance" { + cluster_network_id = "%s" + ip_version = "%s" + ipv4_cidr_block = "%s" + name = "%s" + total_ipv4_address_count = %s + } + + data "ibm_is_cluster_network_subnets" "is_cluster_network_subnets_instance" { + cluster_network_id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_id + name = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.name + sort = "name" + } + `, clusterNetworkSubnetClusterNetworkID, clusterNetworkSubnetIPVersion, clusterNetworkSubnetIpv4CIDRBlock, clusterNetworkSubnetName, clusterNetworkSubnetTotalIpv4AddressCount) +} + +func TestDataSourceIBMIsClusterNetworkSubnetsClusterNetworkSubnetToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + clusterNetworkSubnetLifecycleReasonModel := make(map[string]interface{}) + clusterNetworkSubnetLifecycleReasonModel["code"] = "resource_suspended_by_provider" + clusterNetworkSubnetLifecycleReasonModel["message"] = "The resource has been suspended. Contact IBM support with the CRN for next steps." + clusterNetworkSubnetLifecycleReasonModel["more_info"] = "https://cloud.ibm.com/apidocs/vpc#resource-suspension" + + model := make(map[string]interface{}) + model["available_ipv4_address_count"] = int(15) + model["created_at"] = "2019-01-01T12:00:00.000Z" + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930" + model["id"] = "0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930" + model["ip_version"] = "ipv4" + model["ipv4_cidr_block"] = "10.0.0.0/24" + model["lifecycle_reasons"] = []map[string]interface{}{clusterNetworkSubnetLifecycleReasonModel} + model["lifecycle_state"] = "stable" + model["name"] = "my-cluster-network-subnet" + model["resource_type"] = "cluster_network_subnet" + model["total_ipv4_address_count"] = int(256) + + assert.Equal(t, result, model) + } + + clusterNetworkSubnetLifecycleReasonModel := new(vpcv1.ClusterNetworkSubnetLifecycleReason) + clusterNetworkSubnetLifecycleReasonModel.Code = core.StringPtr("resource_suspended_by_provider") + clusterNetworkSubnetLifecycleReasonModel.Message = core.StringPtr("The resource has been suspended. Contact IBM support with the CRN for next steps.") + clusterNetworkSubnetLifecycleReasonModel.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#resource-suspension") + + model := new(vpcv1.ClusterNetworkSubnet) + model.AvailableIpv4AddressCount = core.Int64Ptr(int64(15)) + model.CreatedAt = CreateMockDateTime("2019-01-01T12:00:00.000Z") + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930") + model.ID = core.StringPtr("0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930") + model.IPVersion = core.StringPtr("ipv4") + model.Ipv4CIDRBlock = core.StringPtr("10.0.0.0/24") + model.LifecycleReasons = []vpcv1.ClusterNetworkSubnetLifecycleReason{*clusterNetworkSubnetLifecycleReasonModel} + model.LifecycleState = core.StringPtr("stable") + model.Name = core.StringPtr("my-cluster-network-subnet") + model.ResourceType = core.StringPtr("cluster_network_subnet") + model.TotalIpv4AddressCount = core.Int64Ptr(int64(256)) + + result, err := vpc.DataSourceIBMIsClusterNetworkSubnetsClusterNetworkSubnetToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkSubnetsClusterNetworkSubnetLifecycleReasonToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["code"] = "resource_suspended_by_provider" + model["message"] = "The resource has been suspended. Contact IBM support with the CRN for next steps." + model["more_info"] = "https://cloud.ibm.com/apidocs/vpc#resource-suspension" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ClusterNetworkSubnetLifecycleReason) + model.Code = core.StringPtr("resource_suspended_by_provider") + model.Message = core.StringPtr("The resource has been suspended. Contact IBM support with the CRN for next steps.") + model.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#resource-suspension") + + result, err := vpc.DataSourceIBMIsClusterNetworkSubnetsClusterNetworkSubnetLifecycleReasonToMap(model) + assert.Nil(t, err) + checkResult(result) +} diff --git a/ibm/service/vpc/data_source_ibm_is_cluster_network_test.go b/ibm/service/vpc/data_source_ibm_is_cluster_network_test.go new file mode 100644 index 0000000000..ed53d12cb3 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_cluster_network_test.go @@ -0,0 +1,287 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_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" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/vpc" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/stretchr/testify/assert" +) + +func TestAccIBMIsClusterNetworkDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsClusterNetworkDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "cluster_network_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "lifecycle_reasons.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "profile.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "profile.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "profile.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "profile.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "resource_group.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "resource_group.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "resource_group.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "resource_group.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "subnet_prefixes.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "subnet_prefixes.0.allocation_policy"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "subnet_prefixes.0.cidr"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "vpc.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "vpc.0.crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "vpc.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "vpc.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "vpc.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "zone.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "zone.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "zone.0.name"), + ), + }, + }, + }) +} + +func TestAccIBMIsClusterNetworkDataSourceAllArgs(t *testing.T) { + clusterNetworkName := fmt.Sprintf("tf_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: testAccCheckIBMIsClusterNetworkDataSourceConfig(clusterNetworkName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "cluster_network_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "lifecycle_reasons.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "lifecycle_reasons.0.code"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "lifecycle_reasons.0.message"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "lifecycle_reasons.0.more_info"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "profile.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "resource_group.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "subnet_prefixes.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "subnet_prefixes.0.allocation_policy"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "subnet_prefixes.0.cidr"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "vpc.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_network.is_cluster_network_instance", "zone.#"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsClusterNetworkDataSourceConfigBasic() string { + return fmt.Sprintf(` + data "ibm_is_cluster_network" "is_cluster_network_instance" { + cluster_network_id = "02c7-10274052-f495-4920-a67f-870eb3b87003" + } + `) +} + +func testAccCheckIBMIsClusterNetworkDataSourceConfig(clusterNetworkName string) string { + return fmt.Sprintf(` + resource "ibm_is_cluster_network" "is_cluster_network_instance" { + name = "%s" + profile { + href = "https://us-south.iaas.cloud.ibm.com/v1/cluster_network/profiles/h100" + name = "h100" + resource_type = "cluster_network_profile" + } + resource_group { + href = "https://resource-controller.cloud.ibm.com/v2/resource_groups/fee82deba12e4c0fb69c3b09d1f12345" + id = "fee82deba12e4c0fb69c3b09d1f12345" + name = "my-resource-group" + } + subnet_prefixes { + allocation_policy = "auto" + cidr = "10.0.0.0/24" + } + vpc { + crn = "crn:v1:bluemix:public:is:us-south:a/aa2432b1fa4d4ace891e9b80fc104e34::vpc:r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + deleted { + more_info = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + } + href = "https://us-south.iaas.cloud.ibm.com/v1/vpcs/r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + id = "r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + name = "my-vpc" + resource_type = "vpc" + } + zone { + href = "https://us-south.iaas.cloud.ibm.com/v1/regions/us-south/zones/us-south-1" + name = "us-south-1" + } + } + + data "ibm_is_cluster_network" "is_cluster_network_instance" { + cluster_network_id = "cluster_network_id" + } + `, clusterNetworkName) +} + +func TestDataSourceIBMIsClusterNetworkClusterNetworkLifecycleReasonToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["code"] = "resource_suspended_by_provider" + model["message"] = "The resource has been suspended. Contact IBM support with the CRN for next steps." + model["more_info"] = "https://cloud.ibm.com/apidocs/vpc#resource-suspension" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ClusterNetworkLifecycleReason) + model.Code = core.StringPtr("resource_suspended_by_provider") + model.Message = core.StringPtr("The resource has been suspended. Contact IBM support with the CRN for next steps.") + model.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#resource-suspension") + + result, err := vpc.DataSourceIBMIsClusterNetworkClusterNetworkLifecycleReasonToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkClusterNetworkProfileReferenceToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/cluster_network/profiles/h100" + model["name"] = "h100" + model["resource_type"] = "cluster_network_profile" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ClusterNetworkProfileReference) + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/cluster_network/profiles/h100") + model.Name = core.StringPtr("h100") + model.ResourceType = core.StringPtr("cluster_network_profile") + + result, err := vpc.DataSourceIBMIsClusterNetworkClusterNetworkProfileReferenceToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkResourceGroupReferenceToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["href"] = "https://resource-controller.cloud.ibm.com/v2/resource_groups/fee82deba12e4c0fb69c3b09d1f12345" + model["id"] = "fee82deba12e4c0fb69c3b09d1f12345" + model["name"] = "my-resource-group" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ResourceGroupReference) + model.Href = core.StringPtr("https://resource-controller.cloud.ibm.com/v2/resource_groups/fee82deba12e4c0fb69c3b09d1f12345") + model.ID = core.StringPtr("fee82deba12e4c0fb69c3b09d1f12345") + model.Name = core.StringPtr("my-resource-group") + + result, err := vpc.DataSourceIBMIsClusterNetworkResourceGroupReferenceToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkClusterNetworkSubnetPrefixToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["allocation_policy"] = "auto" + model["cidr"] = "10.0.0.0/24" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ClusterNetworkSubnetPrefix) + model.AllocationPolicy = core.StringPtr("auto") + model.CIDR = core.StringPtr("10.0.0.0/24") + + result, err := vpc.DataSourceIBMIsClusterNetworkClusterNetworkSubnetPrefixToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkVPCReferenceToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + deletedModel := make(map[string]interface{}) + deletedModel["more_info"] = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + + model := make(map[string]interface{}) + model["crn"] = "crn:v1:bluemix:public:is:us-south:a/aa2432b1fa4d4ace891e9b80fc104e34::vpc:r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + model["deleted"] = []map[string]interface{}{deletedModel} + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/vpcs/r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + model["id"] = "r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + model["name"] = "my-vpc" + model["resource_type"] = "vpc" + + assert.Equal(t, result, model) + } + + deletedModel := new(vpcv1.Deleted) + deletedModel.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#deleted-resources") + + model := new(vpcv1.VPCReference) + model.CRN = core.StringPtr("crn:v1:bluemix:public:is:us-south:a/aa2432b1fa4d4ace891e9b80fc104e34::vpc:r006-4727d842-f94f-4a2d-824a-9bc9b02c523b") + model.Deleted = deletedModel + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/vpcs/r006-4727d842-f94f-4a2d-824a-9bc9b02c523b") + model.ID = core.StringPtr("r006-4727d842-f94f-4a2d-824a-9bc9b02c523b") + model.Name = core.StringPtr("my-vpc") + model.ResourceType = core.StringPtr("vpc") + + result, err := vpc.DataSourceIBMIsClusterNetworkVPCReferenceToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkDeletedToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["more_info"] = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.Deleted) + model.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#deleted-resources") + + result, err := vpc.DataSourceIBMIsClusterNetworkDeletedToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworkZoneReferenceToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/regions/us-south/zones/us-south-1" + model["name"] = "us-south-1" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ZoneReference) + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/regions/us-south/zones/us-south-1") + model.Name = core.StringPtr("us-south-1") + + result, err := vpc.DataSourceIBMIsClusterNetworkZoneReferenceToMap(model) + assert.Nil(t, err) + checkResult(result) +} diff --git a/ibm/service/vpc/data_source_ibm_is_cluster_networks.go b/ibm/service/vpc/data_source_ibm_is_cluster_networks.go new file mode 100644 index 0000000000..6d5bef64a1 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_cluster_networks.go @@ -0,0 +1,440 @@ +// Copyright IBM Corp. 2024 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/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsClusterNetworks() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsClusterNetworksRead, + + Schema: map[string]*schema.Schema{ + "resource_group_id": &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.", + }, + "sort": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "-created_at", + Description: "Sorts the returned collection by the specified property name in ascending order. A `-` may be prepended to the name to sort in descending order. For example, the value `-created_at` sorts the collection by the `created_at` property in descending order, and the value `name` sorts it by the `name` property in ascending order.", + }, + "vpc_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Filters the collection to cluster networks with a `vpc.id` property matching the specified id.", + }, + "vpc_crn": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Filters the collection to cluster networks with a `vpc.crn` property matching the specified CRN.", + }, + "vpc_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Filters the collection to cluster networks with a `vpc.name` property matching the specified name.", + }, + "cluster_networks": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A page of cluster networks.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the cluster network was created.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this cluster network.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network.", + }, + "lifecycle_reasons": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current `lifecycle_state` (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the cluster network.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network. The name must not be used by another cluster network in the region.", + }, + "profile": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The profile for this cluster network.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network profile.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this cluster network profile.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "resource_group": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The resource group for this cluster network.", + 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.", + }, + "subnet_prefixes": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The IP address ranges available for subnets for this cluster network.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allocation_policy": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The allocation policy for this subnet prefix:- `auto`: Subnets created by total count in this cluster network can use this prefix.", + }, + "cidr": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CIDR block for this prefix.", + }, + }, + }, + }, + "vpc": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The VPC this cluster network resides in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this VPC.", + }, + "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 VPC.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this VPC. The name is unique across all VPCs in the region.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "zone": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The zone this cluster network resides in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this zone.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this zone.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsClusterNetworksRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_networks", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + listClusterNetworksOptions := &vpcv1.ListClusterNetworksOptions{} + + if _, ok := d.GetOk("resource_group_id"); ok { + listClusterNetworksOptions.SetResourceGroupID(d.Get("resource_group_id").(string)) + } + if _, ok := d.GetOk("name"); ok { + listClusterNetworksOptions.SetName(d.Get("name").(string)) + } + if _, ok := d.GetOk("sort"); ok { + listClusterNetworksOptions.SetSort(d.Get("sort").(string)) + } + if _, ok := d.GetOk("vpc_id"); ok { + listClusterNetworksOptions.SetVPCID(d.Get("vpc_id").(string)) + } + if _, ok := d.GetOk("vpc_crn"); ok { + listClusterNetworksOptions.SetVPCCRN(d.Get("vpc_crn").(string)) + } + if _, ok := d.GetOk("vpc_name"); ok { + listClusterNetworksOptions.SetVPCName(d.Get("vpc_name").(string)) + } + + var pager *vpcv1.ClusterNetworksPager + pager, err = vpcClient.NewClusterNetworksPager(listClusterNetworksOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_networks", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + allItems, err := pager.GetAll() + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("ClusterNetworksPager.GetAll() failed %s", err), "(Data) ibm_is_cluster_networks", "read") + log.Printf("[DEBUG] %s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(dataSourceIBMIsClusterNetworksID(d)) + + mapSlice := []map[string]interface{}{} + for _, modelItem := range allItems { + modelMap, err := DataSourceIBMIsClusterNetworksClusterNetworkToMap(&modelItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_cluster_networks", "read", "ClusterNetworks-to-map").GetDiag() + } + mapSlice = append(mapSlice, modelMap) + } + + if err = d.Set("cluster_networks", mapSlice); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting cluster_networks %s", err), "(Data) ibm_is_cluster_networks", "read", "cluster_networks-set").GetDiag() + } + + return nil +} + +// dataSourceIBMIsClusterNetworksID returns a reasonable ID for the list. +func dataSourceIBMIsClusterNetworksID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func DataSourceIBMIsClusterNetworksClusterNetworkToMap(model *vpcv1.ClusterNetwork) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["created_at"] = model.CreatedAt.String() + modelMap["crn"] = *model.CRN + modelMap["href"] = *model.Href + modelMap["id"] = *model.ID + lifecycleReasons := []map[string]interface{}{} + for _, lifecycleReasonsItem := range model.LifecycleReasons { + lifecycleReasonsItemMap, err := DataSourceIBMIsClusterNetworksClusterNetworkLifecycleReasonToMap(&lifecycleReasonsItem) // #nosec G601 + if err != nil { + return modelMap, err + } + lifecycleReasons = append(lifecycleReasons, lifecycleReasonsItemMap) + } + modelMap["lifecycle_reasons"] = lifecycleReasons + modelMap["lifecycle_state"] = *model.LifecycleState + modelMap["name"] = *model.Name + profileMap, err := DataSourceIBMIsClusterNetworksClusterNetworkProfileReferenceToMap(model.Profile) + if err != nil { + return modelMap, err + } + modelMap["profile"] = []map[string]interface{}{profileMap} + resourceGroupMap, err := DataSourceIBMIsClusterNetworksResourceGroupReferenceToMap(model.ResourceGroup) + if err != nil { + return modelMap, err + } + modelMap["resource_group"] = []map[string]interface{}{resourceGroupMap} + modelMap["resource_type"] = *model.ResourceType + subnetPrefixes := []map[string]interface{}{} + for _, subnetPrefixesItem := range model.SubnetPrefixes { + subnetPrefixesItemMap, err := DataSourceIBMIsClusterNetworksClusterNetworkSubnetPrefixToMap(&subnetPrefixesItem) // #nosec G601 + if err != nil { + return modelMap, err + } + subnetPrefixes = append(subnetPrefixes, subnetPrefixesItemMap) + } + modelMap["subnet_prefixes"] = subnetPrefixes + vpcMap, err := DataSourceIBMIsClusterNetworksVPCReferenceToMap(model.VPC) + if err != nil { + return modelMap, err + } + modelMap["vpc"] = []map[string]interface{}{vpcMap} + zoneMap, err := DataSourceIBMIsClusterNetworksZoneReferenceToMap(model.Zone) + if err != nil { + return modelMap, err + } + modelMap["zone"] = []map[string]interface{}{zoneMap} + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworksClusterNetworkLifecycleReasonToMap(model *vpcv1.ClusterNetworkLifecycleReason) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["code"] = *model.Code + modelMap["message"] = *model.Message + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworksClusterNetworkProfileReferenceToMap(model *vpcv1.ClusterNetworkProfileReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["name"] = *model.Name + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworksResourceGroupReferenceToMap(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 DataSourceIBMIsClusterNetworksClusterNetworkSubnetPrefixToMap(model *vpcv1.ClusterNetworkSubnetPrefix) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["allocation_policy"] = *model.AllocationPolicy + modelMap["cidr"] = *model.CIDR + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworksVPCReferenceToMap(model *vpcv1.VPCReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = *model.CRN + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsClusterNetworksDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworksDeletedToMap(model *vpcv1.Deleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = *model.MoreInfo + return modelMap, nil +} + +func DataSourceIBMIsClusterNetworksZoneReferenceToMap(model *vpcv1.ZoneReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["name"] = *model.Name + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_cluster_networks_test.go b/ibm/service/vpc/data_source_ibm_is_cluster_networks_test.go new file mode 100644 index 0000000000..0c673f98bf --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_cluster_networks_test.go @@ -0,0 +1,398 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_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" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/service/vpc" + . "github.com/IBM-Cloud/terraform-provider-ibm/ibm/unittest" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/stretchr/testify/assert" +) + +func TestAccIBMIsClusterNetworksDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsClusterNetworksDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.lifecycle_reasons.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.profile.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.profile.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.profile.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.profile.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.resource_group.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.resource_group.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.resource_group.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.resource_group.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.subnet_prefixes.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.subnet_prefixes.0.allocation_policy"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.subnet_prefixes.0.cidr"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.vpc.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.vpc.0.crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.vpc.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.vpc.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.vpc.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.zone.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.zone.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.zone.0.name"), + ), + }, + }, + }) +} + +func TestAccIBMIsClusterNetworksDataSourceAllArgs(t *testing.T) { + clusterNetworkName := fmt.Sprintf("tf_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: testAccCheckIBMIsClusterNetworksDataSourceConfig(clusterNetworkName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "resource_group_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "sort"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "vpc_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "vpc_crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "vpc_name"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.lifecycle_state"), + resource.TestCheckResourceAttr("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.name", clusterNetworkName), + resource.TestCheckResourceAttrSet("data.ibm_is_cluster_networks.is_cluster_networks_instance", "cluster_networks.0.resource_type"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsClusterNetworksDataSourceConfigBasic() string { + return fmt.Sprintf(` + + data "ibm_is_cluster_networks" "is_cluster_networks_instance" { + } + `) +} + +func testAccCheckIBMIsClusterNetworksDataSourceConfig(clusterNetworkName string) string { + return fmt.Sprintf(` + resource "ibm_is_cluster_network" "is_cluster_network_instance" { + name = "%s" + profile { + href = "https://us-south.iaas.cloud.ibm.com/v1/cluster_network/profiles/h100" + name = "h100" + resource_type = "cluster_network_profile" + } + resource_group { + href = "https://resource-controller.cloud.ibm.com/v2/resource_groups/fee82deba12e4c0fb69c3b09d1f12345" + id = "fee82deba12e4c0fb69c3b09d1f12345" + name = "my-resource-group" + } + subnet_prefixes { + allocation_policy = "auto" + cidr = "10.0.0.0/24" + } + vpc { + crn = "crn:v1:bluemix:public:is:us-south:a/aa2432b1fa4d4ace891e9b80fc104e34::vpc:r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + deleted { + more_info = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + } + href = "https://us-south.iaas.cloud.ibm.com/v1/vpcs/r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + id = "r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + name = "my-vpc" + resource_type = "vpc" + } + zone { + href = "https://us-south.iaas.cloud.ibm.com/v1/regions/us-south/zones/us-south-1" + name = "us-south-1" + } + } + + data "ibm_is_cluster_networks" "is_cluster_networks_instance" { + resource_group_id = "resource_group_id" + name = ibm_is_cluster_network.is_cluster_network_instance.name + sort = "name" + vpc_id = "vpc_id" + vpc_crn = "crn:v1:bluemix:public:is:us-south:a/aa2432b1fa4d4ace891e9b80fc104e34::vpc:r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + vpc_name = "my-vpc" + } + `, clusterNetworkName) +} + +func TestDataSourceIBMIsClusterNetworksClusterNetworkToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + clusterNetworkLifecycleReasonModel := make(map[string]interface{}) + clusterNetworkLifecycleReasonModel["code"] = "resource_suspended_by_provider" + clusterNetworkLifecycleReasonModel["message"] = "The resource has been suspended. Contact IBM support with the CRN for next steps." + clusterNetworkLifecycleReasonModel["more_info"] = "https://cloud.ibm.com/apidocs/vpc#resource-suspension" + + clusterNetworkProfileReferenceModel := make(map[string]interface{}) + clusterNetworkProfileReferenceModel["href"] = "https://us-south.iaas.cloud.ibm.com/v1/cluster_network/profiles/h100" + clusterNetworkProfileReferenceModel["name"] = "h100" + clusterNetworkProfileReferenceModel["resource_type"] = "cluster_network_profile" + + resourceGroupReferenceModel := make(map[string]interface{}) + resourceGroupReferenceModel["href"] = "https://resource-controller.cloud.ibm.com/v2/resource_groups/fee82deba12e4c0fb69c3b09d1f12345" + resourceGroupReferenceModel["id"] = "fee82deba12e4c0fb69c3b09d1f12345" + resourceGroupReferenceModel["name"] = "Default" + + clusterNetworkSubnetPrefixModel := make(map[string]interface{}) + clusterNetworkSubnetPrefixModel["allocation_policy"] = "auto" + clusterNetworkSubnetPrefixModel["cidr"] = "10.0.0.0/9" + + deletedModel := make(map[string]interface{}) + deletedModel["more_info"] = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + + vpcReferenceModel := make(map[string]interface{}) + vpcReferenceModel["crn"] = "crn:v1:bluemix:public:is:us-south:a/aa2432b1fa4d4ace891e9b80fc104e34::vpc:r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + vpcReferenceModel["deleted"] = []map[string]interface{}{deletedModel} + vpcReferenceModel["href"] = "https://us-south.iaas.cloud.ibm.com/v1/vpcs/r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + vpcReferenceModel["id"] = "r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + vpcReferenceModel["name"] = "my-vpc" + vpcReferenceModel["resource_type"] = "vpc" + + zoneReferenceModel := make(map[string]interface{}) + zoneReferenceModel["href"] = "https://us-south.iaas.cloud.ibm.com/v1/regions/us-south/zones/us-south-1" + zoneReferenceModel["name"] = "us-south-1" + + model := make(map[string]interface{}) + model["created_at"] = "2019-01-01T12:00:00.000Z" + model["crn"] = "crn:v1:bluemix:public:is:us-south-1:a/aa2432b1fa4d4ace891e9b80fc104e34::cluster-network:0717-da0df18c-7598-4633-a648-fdaac28a5573" + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573" + model["id"] = "0717-da0df18c-7598-4633-a648-fdaac28a5573" + model["lifecycle_reasons"] = []map[string]interface{}{clusterNetworkLifecycleReasonModel} + model["lifecycle_state"] = "stable" + model["name"] = "my-cluster-network" + model["profile"] = []map[string]interface{}{clusterNetworkProfileReferenceModel} + model["resource_group"] = []map[string]interface{}{resourceGroupReferenceModel} + model["resource_type"] = "cluster_network" + model["subnet_prefixes"] = []map[string]interface{}{clusterNetworkSubnetPrefixModel} + model["vpc"] = []map[string]interface{}{vpcReferenceModel} + model["zone"] = []map[string]interface{}{zoneReferenceModel} + + assert.Equal(t, result, model) + } + + clusterNetworkLifecycleReasonModel := new(vpcv1.ClusterNetworkLifecycleReason) + clusterNetworkLifecycleReasonModel.Code = core.StringPtr("resource_suspended_by_provider") + clusterNetworkLifecycleReasonModel.Message = core.StringPtr("The resource has been suspended. Contact IBM support with the CRN for next steps.") + clusterNetworkLifecycleReasonModel.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#resource-suspension") + + clusterNetworkProfileReferenceModel := new(vpcv1.ClusterNetworkProfileReference) + clusterNetworkProfileReferenceModel.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/cluster_network/profiles/h100") + clusterNetworkProfileReferenceModel.Name = core.StringPtr("h100") + clusterNetworkProfileReferenceModel.ResourceType = core.StringPtr("cluster_network_profile") + + resourceGroupReferenceModel := new(vpcv1.ResourceGroupReference) + resourceGroupReferenceModel.Href = core.StringPtr("https://resource-controller.cloud.ibm.com/v2/resource_groups/fee82deba12e4c0fb69c3b09d1f12345") + resourceGroupReferenceModel.ID = core.StringPtr("fee82deba12e4c0fb69c3b09d1f12345") + resourceGroupReferenceModel.Name = core.StringPtr("Default") + + clusterNetworkSubnetPrefixModel := new(vpcv1.ClusterNetworkSubnetPrefix) + clusterNetworkSubnetPrefixModel.AllocationPolicy = core.StringPtr("auto") + clusterNetworkSubnetPrefixModel.CIDR = core.StringPtr("10.0.0.0/9") + + deletedModel := new(vpcv1.Deleted) + deletedModel.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#deleted-resources") + + vpcReferenceModel := new(vpcv1.VPCReference) + vpcReferenceModel.CRN = core.StringPtr("crn:v1:bluemix:public:is:us-south:a/aa2432b1fa4d4ace891e9b80fc104e34::vpc:r006-4727d842-f94f-4a2d-824a-9bc9b02c523b") + vpcReferenceModel.Deleted = deletedModel + vpcReferenceModel.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/vpcs/r006-4727d842-f94f-4a2d-824a-9bc9b02c523b") + vpcReferenceModel.ID = core.StringPtr("r006-4727d842-f94f-4a2d-824a-9bc9b02c523b") + vpcReferenceModel.Name = core.StringPtr("my-vpc") + vpcReferenceModel.ResourceType = core.StringPtr("vpc") + + zoneReferenceModel := new(vpcv1.ZoneReference) + zoneReferenceModel.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/regions/us-south/zones/us-south-1") + zoneReferenceModel.Name = core.StringPtr("us-south-1") + + model := new(vpcv1.ClusterNetwork) + model.CreatedAt = CreateMockDateTime("2019-01-01T12:00:00.000Z") + model.CRN = core.StringPtr("crn:v1:bluemix:public:is:us-south-1:a/aa2432b1fa4d4ace891e9b80fc104e34::cluster-network:0717-da0df18c-7598-4633-a648-fdaac28a5573") + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573") + model.ID = core.StringPtr("0717-da0df18c-7598-4633-a648-fdaac28a5573") + model.LifecycleReasons = []vpcv1.ClusterNetworkLifecycleReason{*clusterNetworkLifecycleReasonModel} + model.LifecycleState = core.StringPtr("stable") + model.Name = core.StringPtr("my-cluster-network") + model.Profile = clusterNetworkProfileReferenceModel + model.ResourceGroup = resourceGroupReferenceModel + model.ResourceType = core.StringPtr("cluster_network") + model.SubnetPrefixes = []vpcv1.ClusterNetworkSubnetPrefix{*clusterNetworkSubnetPrefixModel} + model.VPC = vpcReferenceModel + model.Zone = zoneReferenceModel + + result, err := vpc.DataSourceIBMIsClusterNetworksClusterNetworkToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworksClusterNetworkLifecycleReasonToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["code"] = "resource_suspended_by_provider" + model["message"] = "The resource has been suspended. Contact IBM support with the CRN for next steps." + model["more_info"] = "https://cloud.ibm.com/apidocs/vpc#resource-suspension" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ClusterNetworkLifecycleReason) + model.Code = core.StringPtr("resource_suspended_by_provider") + model.Message = core.StringPtr("The resource has been suspended. Contact IBM support with the CRN for next steps.") + model.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#resource-suspension") + + result, err := vpc.DataSourceIBMIsClusterNetworksClusterNetworkLifecycleReasonToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworksClusterNetworkProfileReferenceToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/cluster_network/profiles/h100" + model["name"] = "h100" + model["resource_type"] = "cluster_network_profile" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ClusterNetworkProfileReference) + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/cluster_network/profiles/h100") + model.Name = core.StringPtr("h100") + model.ResourceType = core.StringPtr("cluster_network_profile") + + result, err := vpc.DataSourceIBMIsClusterNetworksClusterNetworkProfileReferenceToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworksResourceGroupReferenceToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["href"] = "https://resource-controller.cloud.ibm.com/v2/resource_groups/fee82deba12e4c0fb69c3b09d1f12345" + model["id"] = "fee82deba12e4c0fb69c3b09d1f12345" + model["name"] = "my-resource-group" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ResourceGroupReference) + model.Href = core.StringPtr("https://resource-controller.cloud.ibm.com/v2/resource_groups/fee82deba12e4c0fb69c3b09d1f12345") + model.ID = core.StringPtr("fee82deba12e4c0fb69c3b09d1f12345") + model.Name = core.StringPtr("my-resource-group") + + result, err := vpc.DataSourceIBMIsClusterNetworksResourceGroupReferenceToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworksClusterNetworkSubnetPrefixToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["allocation_policy"] = "auto" + model["cidr"] = "10.0.0.0/24" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ClusterNetworkSubnetPrefix) + model.AllocationPolicy = core.StringPtr("auto") + model.CIDR = core.StringPtr("10.0.0.0/24") + + result, err := vpc.DataSourceIBMIsClusterNetworksClusterNetworkSubnetPrefixToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworksVPCReferenceToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + deletedModel := make(map[string]interface{}) + deletedModel["more_info"] = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + + model := make(map[string]interface{}) + model["crn"] = "crn:v1:bluemix:public:is:us-south:a/aa2432b1fa4d4ace891e9b80fc104e34::vpc:r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + model["deleted"] = []map[string]interface{}{deletedModel} + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/vpcs/r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + model["id"] = "r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + model["name"] = "my-vpc" + model["resource_type"] = "vpc" + + assert.Equal(t, result, model) + } + + deletedModel := new(vpcv1.Deleted) + deletedModel.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#deleted-resources") + + model := new(vpcv1.VPCReference) + model.CRN = core.StringPtr("crn:v1:bluemix:public:is:us-south:a/aa2432b1fa4d4ace891e9b80fc104e34::vpc:r006-4727d842-f94f-4a2d-824a-9bc9b02c523b") + model.Deleted = deletedModel + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/vpcs/r006-4727d842-f94f-4a2d-824a-9bc9b02c523b") + model.ID = core.StringPtr("r006-4727d842-f94f-4a2d-824a-9bc9b02c523b") + model.Name = core.StringPtr("my-vpc") + model.ResourceType = core.StringPtr("vpc") + + result, err := vpc.DataSourceIBMIsClusterNetworksVPCReferenceToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworksDeletedToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["more_info"] = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.Deleted) + model.MoreInfo = core.StringPtr("https://cloud.ibm.com/apidocs/vpc#deleted-resources") + + result, err := vpc.DataSourceIBMIsClusterNetworksDeletedToMap(model) + assert.Nil(t, err) + checkResult(result) +} + +func TestDataSourceIBMIsClusterNetworksZoneReferenceToMap(t *testing.T) { + checkResult := func(result map[string]interface{}) { + model := make(map[string]interface{}) + model["href"] = "https://us-south.iaas.cloud.ibm.com/v1/regions/us-south/zones/us-south-1" + model["name"] = "us-south-1" + + assert.Equal(t, result, model) + } + + model := new(vpcv1.ZoneReference) + model.Href = core.StringPtr("https://us-south.iaas.cloud.ibm.com/v1/regions/us-south/zones/us-south-1") + model.Name = core.StringPtr("us-south-1") + + result, err := vpc.DataSourceIBMIsClusterNetworksZoneReferenceToMap(model) + assert.Nil(t, err) + checkResult(result) +} diff --git a/ibm/service/vpc/data_source_ibm_is_image.go b/ibm/service/vpc/data_source_ibm_is_image.go index e848a059d8..ea763c842b 100644 --- a/ibm/service/vpc/data_source_ibm_is_image.go +++ b/ibm/service/vpc/data_source_ibm_is_image.go @@ -386,10 +386,7 @@ func imageGetById(d *schema.ResourceData, meta interface{}, identifier string) e image, response, err := sess.GetImage(getImageOptions) if err != nil { - if response.StatusCode == 404 { - return fmt.Errorf("[ERROR] No image found with id %s", identifier) - } - return fmt.Errorf("[ERROR] Error Fetching Images %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error fetching image with id(%s) %s\n%s", identifier, err, response) } d.SetId(*image.ID) diff --git a/ibm/service/vpc/data_source_ibm_is_image_test.go b/ibm/service/vpc/data_source_ibm_is_image_test.go index 425a160dc5..552d7f0e81 100644 --- a/ibm/service/vpc/data_source_ibm_is_image_test.go +++ b/ibm/service/vpc/data_source_ibm_is_image_test.go @@ -5,6 +5,7 @@ package vpc_test import ( "fmt" + "regexp" "testing" acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" @@ -34,6 +35,20 @@ func TestAccIBMISImageDataSource_basic(t *testing.T) { }, }) } +func TestAccIBMISImageDataSource_id404(t *testing.T) { + imageId := "8843-5fr454ft-f6-4565-9555-5f889f5f3f7777" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISImageDataSource404Config(imageId), + ExpectError: regexp.MustCompile("Error fetching image with id"), + }, + }, + }) +} func TestAccIBMISImageDataSource_All(t *testing.T) { resName := "data.ibm_is_image.test1" imageName := fmt.Sprintf("tfimage-name-%d", acctest.RandIntRange(10, 100)) @@ -171,6 +186,13 @@ func testAccCheckIBMISImageDataSourceConfig(imageName string) string { }`, acc.Image_cos_url, imageName, acc.Image_operating_system) } +func testAccCheckIBMISImageDataSource404Config(imageId string) string { + return fmt.Sprintf(` + data "ibm_is_image" "test1" { + identifier = "%s" + }`, imageId) +} + func testAccCheckIBMISImageDataSourceAllConfig(imageName string) string { return fmt.Sprintf(` data "ibm_is_images" "test1" { diff --git a/ibm/service/vpc/data_source_ibm_is_instance.go b/ibm/service/vpc/data_source_ibm_is_instance.go index 0e1aed9a50..9de35b62af 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance.go +++ b/ibm/service/vpc/data_source_ibm_is_instance.go @@ -17,6 +17,7 @@ import ( "strings" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/go-sdk-core/v5/core" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/ScaleFT/sshkeys" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -62,6 +63,84 @@ func DataSourceIBMISInstance() *schema.Resource { Required: true, Description: "Instance name", }, + // cluster changes + "cluster_network": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, the cluster network that this virtual server instance resides in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this cluster network.", + }, + "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 cluster network.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network. The name must not be used by another cluster network in the region.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "cluster_network_attachments": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The cluster network attachments for this virtual server instance.The cluster network attachments are ordered for consistent instance configuration.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this instance cluster network attachment.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance cluster network attachment.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this instance cluster network attachment. The name is unique across all network attachments for the instance.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, "confidential_compute_mode": &schema.Schema{ Type: schema.TypeString, Computed: true, @@ -1080,6 +1159,35 @@ func DataSourceIBMISInstance() *schema.Resource { }, }, }, + "health_reasons": { + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current health_state (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the reason for this health state.", + }, + "message": { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this health state.", + }, + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this health state.", + }, + }, + }, + }, + "health_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The health of this resource", + }, isInstanceReservation: { Type: schema.TypeList, Computed: true, @@ -1234,6 +1342,32 @@ func instanceGetByName(d *schema.ResourceData, meta interface{}, name string) er d.SetId(*instance.ID) id := *instance.ID + // cluster changes + + if !core.IsNil(instance.ClusterNetwork) { + clusterNetwork := []map[string]interface{}{} + clusterNetworkMap, err := DataSourceIBMIsInstanceClusterNetworkReferenceToMap(instance.ClusterNetwork) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_instance", "read", "cluster_network-to-map") + } + clusterNetwork = append(clusterNetwork, clusterNetworkMap) + if err = d.Set("cluster_network", clusterNetwork); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting cluster_network: %s", err), "(Data) ibm_is_instance", "read", "set-cluster_network") + } + } + + clusterNetworkAttachments := []map[string]interface{}{} + for _, clusterNetworkAttachmentsItem := range instance.ClusterNetworkAttachments { + clusterNetworkAttachmentsItemMap, err := DataSourceIBMIsInstanceInstanceClusterNetworkAttachmentReferenceToMap(&clusterNetworkAttachmentsItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_instance", "read", "cluster_network_attachments-to-map") + } + clusterNetworkAttachments = append(clusterNetworkAttachments, clusterNetworkAttachmentsItemMap) + } + if err = d.Set("cluster_network_attachments", clusterNetworkAttachments); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting cluster_network_attachments: %s", err), "(Data) ibm_is_instance", "read", "set-cluster_network_attachments") + } + // catalog if instance.CatalogOffering != nil { versionCrn := *instance.CatalogOffering.Version.CRN @@ -1651,6 +1785,24 @@ func instanceGetByName(d *schema.ResourceData, meta interface{}, name string) er d.Set(isInstanceResourceGroup, instance.ResourceGroup.ID) d.Set(flex.ResourceGroupName, instance.ResourceGroup.Name) } + if instance.HealthReasons != nil { + healthReasonsList := make([]map[string]interface{}, 0) + for _, sr := range instance.HealthReasons { + currentSR := map[string]interface{}{} + if sr.Code != nil && sr.Message != nil { + currentSR["code"] = *sr.Code + currentSR["message"] = *sr.Message + if sr.MoreInfo != nil { + currentSR["more_info"] = *sr.Message + } + healthReasonsList = append(healthReasonsList, currentSR) + } + } + d.Set("health_reasons", healthReasonsList) + } + if err = d.Set("health_state", instance.HealthState); err != nil { + return err + } if instance.ReservationAffinity != nil { reservationAffinity := []map[string]interface{}{} reservationAffinityMap := map[string]interface{}{} @@ -1668,7 +1820,7 @@ func instanceGetByName(d *schema.ResourceData, meta interface{}, name string) er res[isReservationResourceType] = *pool.ResourceType if pool.Deleted != nil { deletedList := []map[string]interface{}{} - deletedMap := dataSourceInstanceReservationDeletedToMap(*pool.Deleted) + deletedMap := dataSourceReservationDeletedToMap(*pool.Deleted) deletedList = append(deletedList, deletedMap) res[isReservationDeleted] = deletedList } @@ -1690,7 +1842,7 @@ func instanceGetByName(d *schema.ResourceData, meta interface{}, name string) er res[isReservationResourceType] = *instance.Reservation.ResourceType if instance.Reservation.Deleted != nil { deletedList := []map[string]interface{}{} - deletedMap := dataSourceInstanceReservationDeletedToMap(*instance.Reservation.Deleted) + deletedMap := dataSourceReservationDeletedToMap(*instance.Reservation.Deleted) deletedList = append(deletedList, deletedMap) res[isReservationDeleted] = deletedList } @@ -1701,7 +1853,7 @@ func instanceGetByName(d *schema.ResourceData, meta interface{}, name string) er } -func dataSourceInstanceReservationDeletedToMap(deletedItem vpcv1.Deleted) (deletedMap map[string]interface{}) { +func dataSourceReservationDeletedToMap(deletedItem vpcv1.Deleted) (deletedMap map[string]interface{}) { deletedMap = map[string]interface{}{} if deletedItem.MoreInfo != nil { @@ -1880,3 +2032,33 @@ func dataSourceIBMIsInstanceReservedIPReferenceDeletedToMap(model *vpcv1.Deleted modelMap["more_info"] = model.MoreInfo return modelMap, nil } +func DataSourceIBMIsInstanceClusterNetworkReferenceToMap(model *vpcv1.ClusterNetworkReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = *model.CRN + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsInstanceDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsInstanceInstanceClusterNetworkAttachmentReferenceToMap(model *vpcv1.InstanceClusterNetworkAttachmentReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["id"] = *model.ID + modelMap["name"] = *model.Name + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} +func DataSourceIBMIsInstanceDeletedToMap(model *vpcv1.Deleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = *model.MoreInfo + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_cluster_network_attachment.go b/ibm/service/vpc/data_source_ibm_is_instance_cluster_network_attachment.go new file mode 100644 index 0000000000..0bfe21e2d1 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_cluster_network_attachment.go @@ -0,0 +1,402 @@ +// Copyright IBM Corp. 2024 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/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsInstanceClusterNetworkAttachment() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsInstanceClusterNetworkAttachmentRead, + + Schema: map[string]*schema.Schema{ + "instance_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The virtual server instance identifier.", + }, + "instance_cluster_network_attachment_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The instance cluster network attachment identifier.", + }, + "before": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The instance cluster network attachment that is immediately before. If absent, this is thelast instance cluster network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this instance cluster network attachment.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance cluster network attachment.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this instance cluster network attachment. The name is unique across all network attachments for the instance.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "cluster_network_interface": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The cluster network interface for this instance cluster network attachment.", + 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 cluster network interface.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network interface.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network interface. The name is unique across all interfaces in the cluster network.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary IP for this cluster network interface.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address is pending allocation, the value will be `0.0.0.0`.This property may [expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) to support IPv6 addresses in the future.", + }, + "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 cluster network subnet reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network subnet reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network subnet reserved IP. The name is unique across all reserved IPs in a cluster network subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "subnet": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + 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 cluster network subnet.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network subnet. The name is unique across all cluster network subnets in the cluster network.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this instance cluster network attachment.", + }, + "lifecycle_reasons": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current `lifecycle_state` (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the instance cluster network attachment.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this instance cluster network attachment. The name is unique across all network attachments for the instance.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + } +} + +func dataSourceIBMIsInstanceClusterNetworkAttachmentRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_instance_cluster_network_attachment", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + getInstanceClusterNetworkAttachmentOptions := &vpcv1.GetInstanceClusterNetworkAttachmentOptions{} + + getInstanceClusterNetworkAttachmentOptions.SetInstanceID(d.Get("instance_id").(string)) + getInstanceClusterNetworkAttachmentOptions.SetID(d.Get("instance_cluster_network_attachment_id").(string)) + + instanceClusterNetworkAttachment, _, err := vpcClient.GetInstanceClusterNetworkAttachmentWithContext(context, getInstanceClusterNetworkAttachmentOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetInstanceClusterNetworkAttachmentWithContext failed: %s", err.Error()), "(Data) ibm_is_instance_cluster_network_attachment", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(fmt.Sprintf("%s/%s", *getInstanceClusterNetworkAttachmentOptions.InstanceID, *getInstanceClusterNetworkAttachmentOptions.ID)) + + if !core.IsNil(instanceClusterNetworkAttachment.Before) { + before := []map[string]interface{}{} + beforeMap, err := DataSourceIBMIsInstanceClusterNetworkAttachmentInstanceClusterNetworkAttachmentBeforeToMap(instanceClusterNetworkAttachment.Before) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_instance_cluster_network_attachment", "read", "before-to-map").GetDiag() + } + before = append(before, beforeMap) + if err = d.Set("before", before); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting before: %s", err), "(Data) ibm_is_instance_cluster_network_attachment", "read", "set-before").GetDiag() + } + } + + clusterNetworkInterface := []map[string]interface{}{} + clusterNetworkInterfaceMap, err := DataSourceIBMIsInstanceClusterNetworkAttachmentClusterNetworkInterfaceReferenceToMap(instanceClusterNetworkAttachment.ClusterNetworkInterface) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_instance_cluster_network_attachment", "read", "cluster_network_interface-to-map").GetDiag() + } + clusterNetworkInterface = append(clusterNetworkInterface, clusterNetworkInterfaceMap) + if err = d.Set("cluster_network_interface", clusterNetworkInterface); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting cluster_network_interface: %s", err), "(Data) ibm_is_instance_cluster_network_attachment", "read", "set-cluster_network_interface").GetDiag() + } + + if err = d.Set("href", instanceClusterNetworkAttachment.Href); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting href: %s", err), "(Data) ibm_is_instance_cluster_network_attachment", "read", "set-href").GetDiag() + } + + lifecycleReasons := []map[string]interface{}{} + for _, lifecycleReasonsItem := range instanceClusterNetworkAttachment.LifecycleReasons { + lifecycleReasonsItemMap, err := DataSourceIBMIsInstanceClusterNetworkAttachmentInstanceClusterNetworkAttachmentLifecycleReasonToMap(&lifecycleReasonsItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_instance_cluster_network_attachment", "read", "lifecycle_reasons-to-map").GetDiag() + } + lifecycleReasons = append(lifecycleReasons, lifecycleReasonsItemMap) + } + if err = d.Set("lifecycle_reasons", lifecycleReasons); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting lifecycle_reasons: %s", err), "(Data) ibm_is_instance_cluster_network_attachment", "read", "set-lifecycle_reasons").GetDiag() + } + + if err = d.Set("lifecycle_state", instanceClusterNetworkAttachment.LifecycleState); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting lifecycle_state: %s", err), "(Data) ibm_is_instance_cluster_network_attachment", "read", "set-lifecycle_state").GetDiag() + } + + if err = d.Set("name", instanceClusterNetworkAttachment.Name); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting name: %s", err), "(Data) ibm_is_instance_cluster_network_attachment", "read", "set-name").GetDiag() + } + + if err = d.Set("resource_type", instanceClusterNetworkAttachment.ResourceType); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting resource_type: %s", err), "(Data) ibm_is_instance_cluster_network_attachment", "read", "set-resource_type").GetDiag() + } + + return nil +} + +func DataSourceIBMIsInstanceClusterNetworkAttachmentInstanceClusterNetworkAttachmentBeforeToMap(model *vpcv1.InstanceClusterNetworkAttachmentBefore) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["id"] = *model.ID + modelMap["name"] = *model.Name + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsInstanceClusterNetworkAttachmentClusterNetworkInterfaceReferenceToMap(model *vpcv1.ClusterNetworkInterfaceReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsInstanceClusterNetworkAttachmentDeletedToMap(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 + primaryIPMap, err := DataSourceIBMIsInstanceClusterNetworkAttachmentClusterNetworkSubnetReservedIPReferenceToMap(model.PrimaryIP) + if err != nil { + return modelMap, err + } + modelMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + modelMap["resource_type"] = *model.ResourceType + subnetMap, err := DataSourceIBMIsInstanceClusterNetworkAttachmentClusterNetworkSubnetReferenceToMap(model.Subnet) + if err != nil { + return modelMap, err + } + modelMap["subnet"] = []map[string]interface{}{subnetMap} + return modelMap, nil +} + +func DataSourceIBMIsInstanceClusterNetworkAttachmentDeletedToMap(model *vpcv1.Deleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = *model.MoreInfo + return modelMap, nil +} + +func DataSourceIBMIsInstanceClusterNetworkAttachmentClusterNetworkSubnetReservedIPReferenceToMap(model *vpcv1.ClusterNetworkSubnetReservedIPReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["address"] = *model.Address + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsInstanceClusterNetworkAttachmentDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsInstanceClusterNetworkAttachmentClusterNetworkSubnetReferenceToMap(model *vpcv1.ClusterNetworkSubnetReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsInstanceClusterNetworkAttachmentDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsInstanceClusterNetworkAttachmentInstanceClusterNetworkAttachmentLifecycleReasonToMap(model *vpcv1.InstanceClusterNetworkAttachmentLifecycleReason) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["code"] = *model.Code + modelMap["message"] = *model.Message + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_cluster_network_attachment_test.go b/ibm/service/vpc/data_source_ibm_is_instance_cluster_network_attachment_test.go new file mode 100644 index 0000000000..d832370b86 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_cluster_network_attachment_test.go @@ -0,0 +1,123 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_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 TestAccIBMIsInstanceClusterNetworkAttachmentDataSourceBasic(t *testing.T) { + instanceClusterNetworkAttachmentInstanceID := fmt.Sprintf("tf_instance_id_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsInstanceClusterNetworkAttachmentDataSourceConfigBasic(instanceClusterNetworkAttachmentInstanceID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "instance_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "instance_cluster_network_attachment_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "cluster_network_interface.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "lifecycle_reasons.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "resource_type"), + ), + }, + }, + }) +} + +func TestAccIBMIsInstanceClusterNetworkAttachmentDataSourceAllArgs(t *testing.T) { + instanceClusterNetworkAttachmentInstanceID := fmt.Sprintf("tf_instance_id_%d", acctest.RandIntRange(10, 100)) + instanceClusterNetworkAttachmentName := fmt.Sprintf("tf_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: testAccCheckIBMIsInstanceClusterNetworkAttachmentDataSourceConfig(instanceClusterNetworkAttachmentInstanceID, instanceClusterNetworkAttachmentName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "instance_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "instance_cluster_network_attachment_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "before.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "cluster_network_interface.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "cluster_network_interface.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "cluster_network_interface.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "cluster_network_interface.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "cluster_network_interface.0.primary_ip.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "cluster_network_interface.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "cluster_network_interface.0.subnet.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "lifecycle_reasons.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "resource_type"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsInstanceClusterNetworkAttachmentDataSourceConfigBasic(instanceClusterNetworkAttachmentInstanceID string) string { + return fmt.Sprintf(` + resource "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance" { + instance_id = "%s" + cluster_network_interface { + deleted { + more_info = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + } + href = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/interfaces/0717-ffc092f7-5d02-4b93-ab69-26860529b9fb" + id = "0717-ffc092f7-5d02-4b93-ab69-26860529b9fb" + name = "my-cluster-network-interface" + primary_ip { + address = "10.1.0.6" + deleted { + more_info = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + } + href = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930/reserved_ips/6d353a0f-aeb1-4ae1-832e-1110d10981bb" + id = "6d353a0f-aeb1-4ae1-832e-1110d10981bb" + name = "my-cluster-network-subnet-reserved-ip" + resource_type = "cluster_network_subnet_reserved_ip" + } + resource_type = "cluster_network_interface" + subnet { + deleted { + more_info = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + } + href = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930" + id = "0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930" + name = "my-cluster-network-subnet" + resource_type = "cluster_network_subnet" + } + } + } + + data "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance" { + instance_id = ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance.instance_id + instance_cluster_network_attachment_id = ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance.instance_cluster_network_attachment_id + } + `, instanceClusterNetworkAttachmentInstanceID) +} + +func testAccCheckIBMIsInstanceClusterNetworkAttachmentDataSourceConfig(instanceClusterNetworkAttachmentInstanceID string, instanceClusterNetworkAttachmentName string) string { + return fmt.Sprintf(` + data "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance" { + instance_id = "02c7_a8850825-23f1-43f5-92cc-8e97b1c86313" + instance_cluster_network_attachment_id = "02c7-3750a5b5-3efb-46c4-a34e-21f512d99c9d" + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_cluster_network_attachments.go b/ibm/service/vpc/data_source_ibm_is_instance_cluster_network_attachments.go new file mode 100644 index 0000000000..a90de62693 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_cluster_network_attachments.go @@ -0,0 +1,417 @@ +// Copyright IBM Corp. 2024 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/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsInstanceClusterNetworkAttachments() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsInstanceClusterNetworkAttachmentsRead, + + Schema: map[string]*schema.Schema{ + "instance_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The virtual server instance identifier.", + }, + "cluster_network_attachments": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A page of ordered cluster network attachments (sorted based on the `before` property) for the instance. A cluster network attachment represents a device to which a cluster network interface is attached.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "before": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The instance cluster network attachment that is immediately before. If absent, this is thelast instance cluster network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this instance cluster network attachment.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance cluster network attachment.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this instance cluster network attachment. The name is unique across all network attachments for the instance.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "cluster_network_interface": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The cluster network interface for this instance cluster network attachment.", + 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 cluster network interface.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network interface.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network interface. The name is unique across all interfaces in the cluster network.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary IP for this cluster network interface.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address.If the address is pending allocation, the value will be `0.0.0.0`.This property may [expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) to support IPv6 addresses in the future.", + }, + "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 cluster network subnet reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network subnet reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network subnet reserved IP. The name is unique across all reserved IPs in a cluster network subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "subnet": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + 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 cluster network subnet.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network subnet. The name is unique across all cluster network subnets in the cluster network.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + }, + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this instance cluster network attachment.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance cluster network attachment.", + }, + "lifecycle_reasons": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current `lifecycle_state` (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + "more_info": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the instance cluster network attachment.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this instance cluster network attachment. The name is unique across all network attachments for the instance.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsInstanceClusterNetworkAttachmentsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_instance_cluster_network_attachments", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + listInstanceClusterNetworkAttachmentsOptions := &vpcv1.ListInstanceClusterNetworkAttachmentsOptions{} + + listInstanceClusterNetworkAttachmentsOptions.SetInstanceID(d.Get("instance_id").(string)) + + var pager *vpcv1.InstanceClusterNetworkAttachmentsPager + pager, err = vpcClient.NewInstanceClusterNetworkAttachmentsPager(listInstanceClusterNetworkAttachmentsOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_instance_cluster_network_attachments", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + allItems, err := pager.GetAll() + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("InstanceClusterNetworkAttachmentsPager.GetAll() failed %s", err), "(Data) ibm_is_instance_cluster_network_attachments", "read") + log.Printf("[DEBUG] %s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(dataSourceIBMIsInstanceClusterNetworkAttachmentsID(d)) + + mapSlice := []map[string]interface{}{} + for _, modelItem := range allItems { + modelMap, err := DataSourceIBMIsInstanceClusterNetworkAttachmentsInstanceClusterNetworkAttachmentToMap(&modelItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_instance_cluster_network_attachments", "read", "Instances-to-map").GetDiag() + } + mapSlice = append(mapSlice, modelMap) + } + + if err = d.Set("cluster_network_attachments", mapSlice); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting cluster_network_attachments %s", err), "(Data) ibm_is_instance_cluster_network_attachments", "read", "cluster_network_attachments-set").GetDiag() + } + + return nil +} + +// dataSourceIBMIsInstanceClusterNetworkAttachmentsID returns a reasonable ID for the list. +func dataSourceIBMIsInstanceClusterNetworkAttachmentsID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func DataSourceIBMIsInstanceClusterNetworkAttachmentsInstanceClusterNetworkAttachmentToMap(model *vpcv1.InstanceClusterNetworkAttachment) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Before != nil { + beforeMap, err := DataSourceIBMIsInstanceClusterNetworkAttachmentsInstanceClusterNetworkAttachmentBeforeToMap(model.Before) + if err != nil { + return modelMap, err + } + modelMap["before"] = []map[string]interface{}{beforeMap} + } + clusterNetworkInterfaceMap, err := DataSourceIBMIsInstanceClusterNetworkAttachmentsClusterNetworkInterfaceReferenceToMap(model.ClusterNetworkInterface) + if err != nil { + return modelMap, err + } + modelMap["cluster_network_interface"] = []map[string]interface{}{clusterNetworkInterfaceMap} + modelMap["href"] = *model.Href + modelMap["id"] = *model.ID + lifecycleReasons := []map[string]interface{}{} + for _, lifecycleReasonsItem := range model.LifecycleReasons { + lifecycleReasonsItemMap, err := DataSourceIBMIsInstanceClusterNetworkAttachmentsInstanceClusterNetworkAttachmentLifecycleReasonToMap(&lifecycleReasonsItem) // #nosec G601 + if err != nil { + return modelMap, err + } + lifecycleReasons = append(lifecycleReasons, lifecycleReasonsItemMap) + } + modelMap["lifecycle_reasons"] = lifecycleReasons + modelMap["lifecycle_state"] = *model.LifecycleState + modelMap["name"] = *model.Name + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsInstanceClusterNetworkAttachmentsInstanceClusterNetworkAttachmentBeforeToMap(model *vpcv1.InstanceClusterNetworkAttachmentBefore) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["id"] = *model.ID + modelMap["name"] = *model.Name + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsInstanceClusterNetworkAttachmentsClusterNetworkInterfaceReferenceToMap(model *vpcv1.ClusterNetworkInterfaceReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsInstanceClusterNetworkAttachmentsDeletedToMap(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 + primaryIPMap, err := DataSourceIBMIsInstanceClusterNetworkAttachmentsClusterNetworkSubnetReservedIPReferenceToMap(model.PrimaryIP) + if err != nil { + return modelMap, err + } + modelMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + modelMap["resource_type"] = *model.ResourceType + subnetMap, err := DataSourceIBMIsInstanceClusterNetworkAttachmentsClusterNetworkSubnetReferenceToMap(model.Subnet) + if err != nil { + return modelMap, err + } + modelMap["subnet"] = []map[string]interface{}{subnetMap} + return modelMap, nil +} + +func DataSourceIBMIsInstanceClusterNetworkAttachmentsDeletedToMap(model *vpcv1.Deleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = *model.MoreInfo + return modelMap, nil +} + +func DataSourceIBMIsInstanceClusterNetworkAttachmentsClusterNetworkSubnetReservedIPReferenceToMap(model *vpcv1.ClusterNetworkSubnetReservedIPReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["address"] = *model.Address + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsInstanceClusterNetworkAttachmentsDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsInstanceClusterNetworkAttachmentsClusterNetworkSubnetReferenceToMap(model *vpcv1.ClusterNetworkSubnetReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsInstanceClusterNetworkAttachmentsDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsInstanceClusterNetworkAttachmentsInstanceClusterNetworkAttachmentLifecycleReasonToMap(model *vpcv1.InstanceClusterNetworkAttachmentLifecycleReason) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["code"] = *model.Code + modelMap["message"] = *model.Message + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_cluster_network_attachments_test.go b/ibm/service/vpc/data_source_ibm_is_instance_cluster_network_attachments_test.go new file mode 100644 index 0000000000..7928e038ce --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_instance_cluster_network_attachments_test.go @@ -0,0 +1,114 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_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 TestAccIBMIsInstanceClusterNetworkAttachmentsDataSourceBasic(t *testing.T) { + instanceClusterNetworkAttachmentInstanceID := fmt.Sprintf("tf_instance_id_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsInstanceClusterNetworkAttachmentsDataSourceConfigBasic(instanceClusterNetworkAttachmentInstanceID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachments.is_instance_cluster_network_attachments_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachments.is_instance_cluster_network_attachments_instance", "instance_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachments.is_instance_cluster_network_attachments_instance", "cluster_network_attachments.#"), + ), + }, + }, + }) +} + +func TestAccIBMIsInstanceClusterNetworkAttachmentsDataSourceAllArgs(t *testing.T) { + instanceClusterNetworkAttachmentInstanceID := fmt.Sprintf("tf_instance_id_%d", acctest.RandIntRange(10, 100)) + instanceClusterNetworkAttachmentName := fmt.Sprintf("tf_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: testAccCheckIBMIsInstanceClusterNetworkAttachmentsDataSourceConfig(instanceClusterNetworkAttachmentInstanceID, instanceClusterNetworkAttachmentName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachments.is_instance_cluster_network_attachments_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachments.is_instance_cluster_network_attachments_instance", "instance_id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachments.is_instance_cluster_network_attachments_instance", "cluster_network_attachments.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachments.is_instance_cluster_network_attachments_instance", "cluster_network_attachments.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachments.is_instance_cluster_network_attachments_instance", "cluster_network_attachments.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachments.is_instance_cluster_network_attachments_instance", "cluster_network_attachments.0.cluster_network_interface.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachments.is_instance_cluster_network_attachments_instance", "cluster_network_attachments.0.cluster_network_interface.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachments.is_instance_cluster_network_attachments_instance", "cluster_network_attachments.0.cluster_network_interface.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachments.is_instance_cluster_network_attachments_instance", "cluster_network_attachments.0.cluster_network_interface.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachments.is_instance_cluster_network_attachments_instance", "cluster_network_attachments.0.cluster_network_interface.0.primary_ip.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachments.is_instance_cluster_network_attachments_instance", "cluster_network_attachments.0.cluster_network_interface.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachments.is_instance_cluster_network_attachments_instance", "cluster_network_attachments.0.cluster_network_interface.0.subnet.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachments.is_instance_cluster_network_attachments_instance", "cluster_network_attachments.0.lifecycle_reasons.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachments.is_instance_cluster_network_attachments_instance", "cluster_network_attachments.0.lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachments.is_instance_cluster_network_attachments_instance", "cluster_network_attachments.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_cluster_network_attachments.is_instance_cluster_network_attachments_instance", "cluster_network_attachments.0.resource_type"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsInstanceClusterNetworkAttachmentsDataSourceConfigBasic(instanceClusterNetworkAttachmentInstanceID string) string { + return fmt.Sprintf(` + resource "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance" { + instance_id = "%s" + cluster_network_interface { + deleted { + more_info = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + } + href = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/interfaces/0717-ffc092f7-5d02-4b93-ab69-26860529b9fb" + id = "0717-ffc092f7-5d02-4b93-ab69-26860529b9fb" + name = "my-cluster-network-interface" + primary_ip { + address = "10.1.0.6" + deleted { + more_info = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + } + href = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930/reserved_ips/6d353a0f-aeb1-4ae1-832e-1110d10981bb" + id = "6d353a0f-aeb1-4ae1-832e-1110d10981bb" + name = "my-cluster-network-subnet-reserved-ip" + resource_type = "cluster_network_subnet_reserved_ip" + } + resource_type = "cluster_network_interface" + subnet { + deleted { + more_info = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + } + href = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930" + id = "0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930" + name = "my-cluster-network-subnet" + resource_type = "cluster_network_subnet" + } + } + } + + data "ibm_is_instance_cluster_network_attachments" "is_instance_cluster_network_attachments_instance" { + instance_id = ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance.instance_id + } + `, instanceClusterNetworkAttachmentInstanceID) +} + +func testAccCheckIBMIsInstanceClusterNetworkAttachmentsDataSourceConfig(instanceClusterNetworkAttachmentInstanceID string, instanceClusterNetworkAttachmentName string) string { + return fmt.Sprintf(` + data "ibm_is_instance_cluster_network_attachments" "is_instance_cluster_network_attachments_instance" { + instance_id = "02c7_a8850825-23f1-43f5-92cc-8e97b1c86313" + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_profile.go b/ibm/service/vpc/data_source_ibm_is_instance_profile.go index 8dcafcc12a..741e27d93b 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_profile.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_profile.go @@ -6,6 +6,7 @@ package vpc import ( "fmt" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -29,6 +30,72 @@ func DataSourceIBMISInstanceProfile() *schema.Resource { Required: true, }, + // cluster changes + "cluster_network_attachment_count": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "default": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + }, + "values": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The permitted values for this profile field.", + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + "max": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The maximum value for this profile field.", + }, + "min": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The minimum value for this profile field.", + }, + "step": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + + "supported_cluster_network_profiles": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The cluster network profiles that support this instance profile.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network profile.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this cluster network profile.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "confidential_compute_modes": &schema.Schema{ Type: schema.TypeList, Computed: true, @@ -766,6 +833,29 @@ func instanceProfileGet(d *schema.ResourceData, meta interface{}, name string) e d.Set("status", profile.Status) } + // cluster changes + clusterNetworkAttachmentCount := []map[string]interface{}{} + clusterNetworkAttachmentCountMap, err := DataSourceIBMIsInstanceProfileInstanceProfileClusterNetworkAttachmentCountToMap(profile.ClusterNetworkAttachmentCount) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_instance_profile", "read", "cluster_network_attachment_count-to-map") + } + clusterNetworkAttachmentCount = append(clusterNetworkAttachmentCount, clusterNetworkAttachmentCountMap) + if err = d.Set("cluster_network_attachment_count", clusterNetworkAttachmentCount); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting cluster_network_attachment_count: %s", err), "(Data) ibm_is_instance_profile", "read", "set-cluster_network_attachment_count") + } + + supportedClusterNetworkProfiles := []map[string]interface{}{} + for _, supportedClusterNetworkProfilesItem := range profile.SupportedClusterNetworkProfiles { + supportedClusterNetworkProfilesItemMap, err := DataSourceIBMIsInstanceProfileClusterNetworkProfileReferenceToMap(&supportedClusterNetworkProfilesItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_instance_profile", "read", "supported_cluster_network_profiles-to-map") + } + supportedClusterNetworkProfiles = append(supportedClusterNetworkProfiles, supportedClusterNetworkProfilesItemMap) + } + if err = d.Set("supported_cluster_network_profiles", supportedClusterNetworkProfiles); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting supported_cluster_network_profiles: %s", err), "(Data) ibm_is_instance_profile", "read", "set-supported_cluster_network_profiles") + } + confidentialComputeModes := []map[string]interface{}{} if profile.ConfidentialComputeModes != nil { modelMap, err := dataSourceIBMIsInstanceProfileInstanceProfileSupportedConfidentialComputeModesToMap(profile.ConfidentialComputeModes) @@ -1432,3 +1522,76 @@ func dataSourceIBMIsInstanceProfileInstanceProfileSupportedConfidentialComputeMo modelMap["values"] = model.Values return modelMap, nil } + +func DataSourceIBMIsInstanceProfileInstanceProfileClusterNetworkAttachmentCountToMap(model vpcv1.InstanceProfileClusterNetworkAttachmentCountIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.InstanceProfileClusterNetworkAttachmentCountDependent); ok { + return DataSourceIBMIsInstanceProfileInstanceProfileClusterNetworkAttachmentCountDependentToMap(model.(*vpcv1.InstanceProfileClusterNetworkAttachmentCountDependent)) + } else if _, ok := model.(*vpcv1.InstanceProfileClusterNetworkAttachmentCountEnum); ok { + return DataSourceIBMIsInstanceProfileInstanceProfileClusterNetworkAttachmentCountEnumToMap(model.(*vpcv1.InstanceProfileClusterNetworkAttachmentCountEnum)) + } else if _, ok := model.(*vpcv1.InstanceProfileClusterNetworkAttachmentCountRange); ok { + return DataSourceIBMIsInstanceProfileInstanceProfileClusterNetworkAttachmentCountRangeToMap(model.(*vpcv1.InstanceProfileClusterNetworkAttachmentCountRange)) + } else if _, ok := model.(*vpcv1.InstanceProfileClusterNetworkAttachmentCount); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.InstanceProfileClusterNetworkAttachmentCount) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Default != nil { + modelMap["default"] = flex.IntValue(model.Default) + } + if model.Values != nil { + modelMap["values"] = model.Values + } + if model.Max != nil { + modelMap["max"] = flex.IntValue(model.Max) + } + if model.Min != nil { + modelMap["min"] = flex.IntValue(model.Min) + } + if model.Step != nil { + modelMap["step"] = flex.IntValue(model.Step) + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.InstanceProfileClusterNetworkAttachmentCountIntf subtype encountered") + } +} + +func DataSourceIBMIsInstanceProfileInstanceProfileClusterNetworkAttachmentCountDependentToMap(model *vpcv1.InstanceProfileClusterNetworkAttachmentCountDependent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["type"] = *model.Type + return modelMap, nil +} + +func DataSourceIBMIsInstanceProfileInstanceProfileClusterNetworkAttachmentCountEnumToMap(model *vpcv1.InstanceProfileClusterNetworkAttachmentCountEnum) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Default != nil { + modelMap["default"] = flex.IntValue(model.Default) + } + modelMap["type"] = *model.Type + modelMap["values"] = model.Values + return modelMap, nil +} + +func DataSourceIBMIsInstanceProfileInstanceProfileClusterNetworkAttachmentCountRangeToMap(model *vpcv1.InstanceProfileClusterNetworkAttachmentCountRange) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Max != nil { + modelMap["max"] = flex.IntValue(model.Max) + } + if model.Min != nil { + modelMap["min"] = flex.IntValue(model.Min) + } + if model.Step != nil { + modelMap["step"] = flex.IntValue(model.Step) + } + modelMap["type"] = *model.Type + return modelMap, nil +} + +func DataSourceIBMIsInstanceProfileClusterNetworkProfileReferenceToMap(model *vpcv1.ClusterNetworkProfileReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["name"] = *model.Name + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_profile_test.go b/ibm/service/vpc/data_source_ibm_is_instance_profile_test.go index 416b6d8e64..a43c45e14b 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_profile_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_profile_test.go @@ -46,6 +46,47 @@ func TestAccIBMISInstanceProfileDataSource_basic(t *testing.T) { }, }) } +func TestAccIBMISInstanceProfileDataSource_cluster(t *testing.T) { + resName := "data.ibm_is_instance_profile.test1" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceProfileDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resName, "name", acc.InstanceProfileName), + resource.TestCheckResourceAttrSet(resName, "family"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "bandwidth.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "cluster_network_attachment_count.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "cluster_network_attachment_count.0.values.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "confidential_compute_modes.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "disks.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "family"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "href"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "memory.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "network_attachment_count.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "network_interface_count.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "port_speed.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "reservation_terms.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "secure_boot_modes.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "status"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "supported_cluster_network_profiles.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "supported_cluster_network_profiles.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "supported_cluster_network_profiles.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "supported_cluster_network_profiles.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "total_volume_bandwidth.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "vcpu_architecture.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "vcpu_count.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profile.test1", "vcpu_manufacturer.#"), + ), + }, + }, + }) +} func TestAccIBMISInstanceProfileDataSource_concom(t *testing.T) { resName := "data.ibm_is_instance_profile.test1" diff --git a/ibm/service/vpc/data_source_ibm_is_instance_profiles.go b/ibm/service/vpc/data_source_ibm_is_instance_profiles.go index 8fce1b1da1..d4d18ef1c2 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_profiles.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_profiles.go @@ -7,6 +7,7 @@ import ( "fmt" "time" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -36,6 +37,71 @@ func DataSourceIBMISInstanceProfiles() *schema.Resource { Computed: true, Description: "The product family this virtual server instance profile belongs to.", }, + + // cluster changes + "cluster_network_attachment_count": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The type for this profile field.", + }, + "default": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + }, + "values": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The permitted values for this profile field.", + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + "max": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The maximum value for this profile field.", + }, + "min": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The minimum value for this profile field.", + }, + "step": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + "supported_cluster_network_profiles": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The cluster network profiles that support this instance profile.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network profile.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this cluster network profile.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, "confidential_compute_modes": &schema.Schema{ Type: schema.TypeList, Computed: true, @@ -771,6 +837,24 @@ func instanceProfilesList(d *schema.ResourceData, meta interface{}) error { l["bandwidth"] = bandwidthList } + // cluster changes + + supportedClusterNetworkProfiles := []map[string]interface{}{} + for _, supportedClusterNetworkProfilesItem := range profile.SupportedClusterNetworkProfiles { + supportedClusterNetworkProfilesItemMap, err := DataSourceIBMIsInstanceProfilesClusterNetworkProfileReferenceToMap(&supportedClusterNetworkProfilesItem) // #nosec G601 + if err != nil { + return err + } + supportedClusterNetworkProfiles = append(supportedClusterNetworkProfiles, supportedClusterNetworkProfilesItemMap) + } + l["supported_cluster_network_profiles"] = supportedClusterNetworkProfiles + + clusterNetworkAttachmentCountMap, err := DataSourceIBMIsInstanceProfilesInstanceProfileClusterNetworkAttachmentCountToMap(profile.ClusterNetworkAttachmentCount) + if err != nil { + return err + } + l["cluster_network_attachment_count"] = []map[string]interface{}{clusterNetworkAttachmentCountMap} + if profile.GpuCount != nil { l["gpu_count"] = dataSourceInstanceProfileFlattenGPUCount(*profile.GpuCount.(*vpcv1.InstanceProfileGpu)) } @@ -893,3 +977,76 @@ func instanceProfilesList(d *schema.ResourceData, meta interface{}) error { func dataSourceIBMISInstanceProfilesID(d *schema.ResourceData) string { return time.Now().UTC().String() } + +func DataSourceIBMIsInstanceProfilesClusterNetworkProfileReferenceToMap(model *vpcv1.ClusterNetworkProfileReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["name"] = *model.Name + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsInstanceProfilesInstanceProfileClusterNetworkAttachmentCountToMap(model vpcv1.InstanceProfileClusterNetworkAttachmentCountIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.InstanceProfileClusterNetworkAttachmentCountDependent); ok { + return DataSourceIBMIsInstanceProfilesInstanceProfileClusterNetworkAttachmentCountDependentToMap(model.(*vpcv1.InstanceProfileClusterNetworkAttachmentCountDependent)) + } else if _, ok := model.(*vpcv1.InstanceProfileClusterNetworkAttachmentCountEnum); ok { + return DataSourceIBMIsInstanceProfilesInstanceProfileClusterNetworkAttachmentCountEnumToMap(model.(*vpcv1.InstanceProfileClusterNetworkAttachmentCountEnum)) + } else if _, ok := model.(*vpcv1.InstanceProfileClusterNetworkAttachmentCountRange); ok { + return DataSourceIBMIsInstanceProfilesInstanceProfileClusterNetworkAttachmentCountRangeToMap(model.(*vpcv1.InstanceProfileClusterNetworkAttachmentCountRange)) + } else if _, ok := model.(*vpcv1.InstanceProfileClusterNetworkAttachmentCount); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.InstanceProfileClusterNetworkAttachmentCount) + if model.Type != nil { + modelMap["type"] = *model.Type + } + if model.Default != nil { + modelMap["default"] = flex.IntValue(model.Default) + } + if model.Values != nil { + modelMap["values"] = model.Values + } + if model.Max != nil { + modelMap["max"] = flex.IntValue(model.Max) + } + if model.Min != nil { + modelMap["min"] = flex.IntValue(model.Min) + } + if model.Step != nil { + modelMap["step"] = flex.IntValue(model.Step) + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.InstanceProfileClusterNetworkAttachmentCountIntf subtype encountered") + } +} + +func DataSourceIBMIsInstanceProfilesInstanceProfileClusterNetworkAttachmentCountDependentToMap(model *vpcv1.InstanceProfileClusterNetworkAttachmentCountDependent) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["type"] = *model.Type + return modelMap, nil +} + +func DataSourceIBMIsInstanceProfilesInstanceProfileClusterNetworkAttachmentCountEnumToMap(model *vpcv1.InstanceProfileClusterNetworkAttachmentCountEnum) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Default != nil { + modelMap["default"] = flex.IntValue(model.Default) + } + modelMap["type"] = *model.Type + modelMap["values"] = model.Values + return modelMap, nil +} + +func DataSourceIBMIsInstanceProfilesInstanceProfileClusterNetworkAttachmentCountRangeToMap(model *vpcv1.InstanceProfileClusterNetworkAttachmentCountRange) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Max != nil { + modelMap["max"] = flex.IntValue(model.Max) + } + if model.Min != nil { + modelMap["min"] = flex.IntValue(model.Min) + } + if model.Step != nil { + modelMap["step"] = flex.IntValue(model.Step) + } + modelMap["type"] = *model.Type + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_profiles_test.go b/ibm/service/vpc/data_source_ibm_is_instance_profiles_test.go index f14b6e9222..0bea56e11e 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_profiles_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_profiles_test.go @@ -47,6 +47,44 @@ func TestAccIBMISInstanceProfilesDataSource_basic(t *testing.T) { }, }) } +func TestAccIBMISInstanceProfilesDataSource_cluster(t *testing.T) { + resName := "data.ibm_is_instance_profiles.test1" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceProfilesDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(resName, "profiles.0.name"), + resource.TestCheckResourceAttrSet(resName, "profiles.0.family"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profiles.test1", "profiles.0.bandwidth.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profiles.test1", "profiles.0.family"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profiles.test1", "profiles.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profiles.test1", "profiles.0.memory.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profiles.test1", "profiles.0.architecture"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profiles.test1", "profiles.0.port_speed.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profiles.test1", "profiles.0.vcpu_architecture.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profiles.test1", "profiles.0.vcpu_count.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profiles.test1", "profiles.0.network_interface_count.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profiles.test1", "profiles.0.network_interface_count.0.type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profiles.test1", "profiles.0.network_attachment_count.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profiles.test1", "profiles.0.network_attachment_count.0.type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profiles.test1", "profiles.0.vcpu_manufacturer.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profiles.test1", "profiles.0.vcpu_manufacturer.0.type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profiles.test1", "profiles.0.vcpu_manufacturer.0.value"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profiles.test1", "profiles.0.reservation_terms.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profiles.test1", "profiles.0.reservation_terms.0.type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profiles.test1", "profiles.0.reservation_terms.0.values.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profiles.test1", "profiles.0.cluster_network_attachment_count.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profiles.test1", "profiles.0.cluster_network_attachment_count.0.values.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance_profiles.test1", "profiles.0.supported_cluster_network_profiles.#"), + ), + }, + }, + }) +} func TestAccIBMISInstanceProfilesDataSource_concom(t *testing.T) { resName := "data.ibm_is_instance_profiles.test1" diff --git a/ibm/service/vpc/data_source_ibm_is_instance_template.go b/ibm/service/vpc/data_source_ibm_is_instance_template.go index ff34bfbc8d..65292e0f6c 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_template.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_template.go @@ -11,6 +11,7 @@ import ( "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" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -75,6 +76,104 @@ func DataSourceIBMISInstanceTemplate() *schema.Resource { Computed: true, ExactlyOneOf: []string{"identifier", isInstanceTemplateName}, }, + + // cluster changes + "cluster_network_attachments": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The cluster network attachments to create for this virtual server instance. A cluster network attachment represents a device that is connected to a cluster network. The number of network attachments must match one of the values from the instance profile's `cluster_network_attachment_count` before the instance can be started.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cluster_network_interface": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A cluster network interface for the instance cluster network attachment. This can bespecified using an existing cluster network interface that does not already have a `target`,or a prototype object for a new cluster network interface.This instance must reside in the same VPC as the specified cluster network interface. Thecluster network interface must reside in the same cluster network as the`cluster_network_interface` of any other `cluster_network_attachments` for this instance.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this cluster network interface will be automatically deleted when `target` is deleted.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network interface. The name must not be used by another interface in the cluster network. Names beginning with `ibm-` are reserved for provider-owned resources, and are not allowed. If unspecified, the name will be a hyphenated list of randomly-selected words.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address to bind to the cluster network interface. May be eithera cluster network subnet reserved IP identity, or a cluster network subnet reserved IPprototype object which will be used to create a new cluster network subnet reserved IP.If a cluster network subnet reserved IP identity is provided, the specified clusternetwork subnet reserved IP must be unbound.If a cluster network subnet reserved IP prototype object with an address is provided,the address must be available on the cluster network interface's cluster networksubnet. If no address is specified, an available address on the cluster network subnetwill be automatically selected and reserved.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network subnet reserved IP.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network subnet reserved IP.", + }, + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.If unspecified, an available address on the subnet will automatically be selected.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this cluster network subnet reserved IP member will be automatically deleted when either `target` is deleted, or the cluster network subnet reserved IP is unbound.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network subnet reserved IP. The name must not be used by another reserved IP in the cluster network subnet. Names starting with `ibm-` are reserved for provider-owned resources, and are not allowed. If unspecified, the name will be a hyphenated list of randomly-selected words.", + }, + }, + }, + }, + "subnet": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The associated cluster network subnet. Required if `primary_ip` does not specify acluster network subnet reserved IP identity.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network subnet.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network subnet.", + }, + }, + }, + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network interface.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network interface.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network attachment. Names must be unique within the instance the cluster network attachment resides in. If unspecified, the name will be a hyphenated list of randomly-selected words. Names starting with `ibm-` are reserved for provider-owned resources, and are not allowed.", + }, + }, + }, + }, "confidential_compute_mode": &schema.Schema{ Type: schema.TypeString, Computed: true, @@ -895,6 +994,21 @@ func dataSourceIBMISInstanceTemplateRead(context context.Context, d *schema.Reso } } + // cluster changes + if !core.IsNil(instance.ClusterNetworkAttachments) { + clusterNetworkAttachments := []map[string]interface{}{} + for _, clusterNetworkAttachmentsItem := range instance.ClusterNetworkAttachments { + clusterNetworkAttachmentsItemMap, err := DataSourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeInstanceContextToMap(&clusterNetworkAttachmentsItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_instance_template", "read", "cluster_network_attachments-to-map").GetDiag() + } + clusterNetworkAttachments = append(clusterNetworkAttachments, clusterNetworkAttachmentsItemMap) + } + if err = d.Set("cluster_network_attachments", clusterNetworkAttachments); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting cluster_network_attachments: %s", err), "(Data) ibm_is_instance_template", "read", "set-cluster_network_attachments").GetDiag() + } + } + // catalog offering if any if instance.CatalogOffering != nil { catOfferingList := make([]map[string]interface{}, 0) @@ -1205,6 +1319,21 @@ func dataSourceIBMISInstanceTemplateRead(context context.Context, d *schema.Reso if err = d.Set("enable_secure_boot", instance.EnableSecureBoot); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting enable_secure_boot: %s", err)) } + // cluster changes + if !core.IsNil(instance.ClusterNetworkAttachments) { + clusterNetworkAttachments := []map[string]interface{}{} + for _, clusterNetworkAttachmentsItem := range instance.ClusterNetworkAttachments { + clusterNetworkAttachmentsItemMap, err := DataSourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeInstanceContextToMap(&clusterNetworkAttachmentsItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "(Data) ibm_is_instance_template", "read", "cluster_network_attachments-to-map").GetDiag() + } + clusterNetworkAttachments = append(clusterNetworkAttachments, clusterNetworkAttachmentsItemMap) + } + if err = d.Set("cluster_network_attachments", clusterNetworkAttachments); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting cluster_network_attachments: %s", err), "(Data) ibm_is_instance_template", "read", "set-cluster_network_attachments").GetDiag() + } + } + // catalog offering if any if instance.CatalogOffering != nil { catOfferingList := make([]map[string]interface{}, 0) @@ -2175,3 +2304,220 @@ func dataSourceIBMIsInstanceTemplateInstanceCatalogOfferingPrototypeCatalogOffer modelMap["version"] = []map[string]interface{}{versionMap} return modelMap, nil } + +func DataSourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeInstanceContextToMap(model *vpcv1.InstanceClusterNetworkAttachmentPrototypeInstanceContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + clusterNetworkInterfaceMap, err := DataSourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceToMap(model.ClusterNetworkInterface) + if err != nil { + return modelMap, err + } + modelMap["cluster_network_interface"] = []map[string]interface{}{clusterNetworkInterfaceMap} + if model.Name != nil { + modelMap["name"] = *model.Name + } + return modelMap, nil +} + +func DataSourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceToMap(model vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceInstanceClusterNetworkInterfacePrototypeInstanceClusterNetworkAttachment); ok { + return DataSourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceInstanceClusterNetworkInterfacePrototypeInstanceClusterNetworkAttachmentToMap(model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceInstanceClusterNetworkInterfacePrototypeInstanceClusterNetworkAttachment)) + } else if _, ok := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentity); ok { + return DataSourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityToMap(model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentity)) + } else if _, ok := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterface); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterface) + if model.AutoDelete != nil { + modelMap["auto_delete"] = *model.AutoDelete + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.PrimaryIP != nil { + primaryIPMap, err := DataSourceIBMIsInstanceTemplateClusterNetworkInterfacePrimaryIPPrototypeToMap(model.PrimaryIP) + if err != nil { + return modelMap, err + } + modelMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + } + if model.Subnet != nil { + subnetMap, err := DataSourceIBMIsInstanceTemplateClusterNetworkSubnetIdentityToMap(model.Subnet) + if err != nil { + return modelMap, err + } + modelMap["subnet"] = []map[string]interface{}{subnetMap} + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceIntf subtype encountered") + } +} + +func DataSourceIBMIsInstanceTemplateClusterNetworkInterfacePrimaryIPPrototypeToMap(model vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContext); ok { + return DataSourceIBMIsInstanceTemplateClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextToMap(model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContext)) + } else if _, ok := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContext); ok { + return DataSourceIBMIsInstanceTemplateClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContextToMap(model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContext)) + } else if _, ok := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototype); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototype) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + if model.Address != nil { + modelMap["address"] = *model.Address + } + if model.AutoDelete != nil { + modelMap["auto_delete"] = *model.AutoDelete + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeIntf subtype encountered") + } +} + +func DataSourceIBMIsInstanceTemplateClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextToMap(model vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByID); ok { + return DataSourceIBMIsInstanceTemplateClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByIDToMap(model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByID)) + } else if _, ok := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHref); ok { + return DataSourceIBMIsInstanceTemplateClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHrefToMap(model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHref)) + } else if _, ok := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContext); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContext) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextIntf subtype encountered") + } +} + +func DataSourceIBMIsInstanceTemplateClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByIDToMap(model *vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByID) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = *model.ID + return modelMap, nil +} + +func DataSourceIBMIsInstanceTemplateClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHrefToMap(model *vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHref) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + return modelMap, nil +} + +func DataSourceIBMIsInstanceTemplateClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContextToMap(model *vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Address != nil { + modelMap["address"] = *model.Address + } + if model.AutoDelete != nil { + modelMap["auto_delete"] = *model.AutoDelete + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + return modelMap, nil +} + +func DataSourceIBMIsInstanceTemplateClusterNetworkSubnetIdentityToMap(model vpcv1.ClusterNetworkSubnetIdentityIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.ClusterNetworkSubnetIdentityByID); ok { + return DataSourceIBMIsInstanceTemplateClusterNetworkSubnetIdentityByIDToMap(model.(*vpcv1.ClusterNetworkSubnetIdentityByID)) + } else if _, ok := model.(*vpcv1.ClusterNetworkSubnetIdentityByHref); ok { + return DataSourceIBMIsInstanceTemplateClusterNetworkSubnetIdentityByHrefToMap(model.(*vpcv1.ClusterNetworkSubnetIdentityByHref)) + } else if _, ok := model.(*vpcv1.ClusterNetworkSubnetIdentity); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.ClusterNetworkSubnetIdentity) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.ClusterNetworkSubnetIdentityIntf subtype encountered") + } +} + +func DataSourceIBMIsInstanceTemplateClusterNetworkSubnetIdentityByIDToMap(model *vpcv1.ClusterNetworkSubnetIdentityByID) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = *model.ID + return modelMap, nil +} + +func DataSourceIBMIsInstanceTemplateClusterNetworkSubnetIdentityByHrefToMap(model *vpcv1.ClusterNetworkSubnetIdentityByHref) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + return modelMap, nil +} + +func DataSourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceInstanceClusterNetworkInterfacePrototypeInstanceClusterNetworkAttachmentToMap(model *vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceInstanceClusterNetworkInterfacePrototypeInstanceClusterNetworkAttachment) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.AutoDelete != nil { + modelMap["auto_delete"] = *model.AutoDelete + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.PrimaryIP != nil { + primaryIPMap, err := DataSourceIBMIsInstanceTemplateClusterNetworkInterfacePrimaryIPPrototypeToMap(model.PrimaryIP) + if err != nil { + return modelMap, err + } + modelMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + } + if model.Subnet != nil { + subnetMap, err := DataSourceIBMIsInstanceTemplateClusterNetworkSubnetIdentityToMap(model.Subnet) + if err != nil { + return modelMap, err + } + modelMap["subnet"] = []map[string]interface{}{subnetMap} + } + return modelMap, nil +} + +func DataSourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityToMap(model vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByID); ok { + return DataSourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByIDToMap(model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByID)) + } else if _, ok := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByHref); ok { + return DataSourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByHrefToMap(model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByHref)) + } else if _, ok := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentity); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentity) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityIntf subtype encountered") + } +} + +func DataSourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByIDToMap(model *vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByID) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = *model.ID + return modelMap, nil +} + +func DataSourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByHrefToMap(model *vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByHref) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_template_test.go b/ibm/service/vpc/data_source_ibm_is_instance_template_test.go index d1f560f3ba..4846a776d0 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_template_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_template_test.go @@ -40,6 +40,61 @@ func TestAccIBMISInstanceTemplate_dataBasic(t *testing.T) { }, }) } +func TestAccIBMISInstanceTemplateDatasourceCluster(t *testing.T) { + randInt := acctest.RandIntRange(600, 700) + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQ+WiiUR1Jg3oGSmB/2//GJ3XnotriBiGN6t3iwGces6sUsvRkza1t0Mf05DKZxC/zp0WvDTvbit2gTkF9sD37OZSn5aCJk1F5URk/JNPmz25ZogkICFL4OUfhrE3mnyKio6Bk1JIEIypR5PRtGxY9vFDUfruADDLfRi+dGwHF6U9RpvrDRo3FNtI8T0GwvWwFE7bg63vLz65CjYY5XqH9z/YWz/asH6BKumkwiphLGhuGn03+DV6DkIZqr3Oh13UDjMnTdgv1y/Kou5UM3CK1dVsmLRXPEf2KUWUq1EwRfrJXkPOrBwn8to+Yydo57FgrRM9Qw8uzvKmnVxfKW6iG3oSGA0L6ROuCq1lq0MD8ySLd56+d1ftSDaUq+0/Yt9vK3olzVP0/iZobD7chbGqTLMCzL4/CaIUR/UmX08EA0Oh0DdyAdj3UUNETAj3W8gBrV6xLR7fZAJ8roX2BKb4K8Ed3YqzgiY0zgjqvpBYl9xZl0jgVX0qMFaEa6+CeGI8= root@ffd8363b1226 + `) + vpcName := fmt.Sprintf("testvpc%d", randInt) + subnetName := fmt.Sprintf("testsubnet%d", randInt) + // templateName := fmt.Sprintf("testtemplate%d", randInt) + templateName := "eu-de-test-cluster-it" + sshKeyName := fmt.Sprintf("testsshkey%d", randInt) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceTemplateDatasourceClusterConfig(vpcName, subnetName, sshKeyName, publicKey, templateName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "data.ibm_is_instance_template.instance_template_data_name", "name", templateName), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data_name", "boot_volume_attachment.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data_name", "cluster_network_attachments.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data_name", "cluster_network_attachments.0.cluster_network_interface.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data_name", "crn"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data_name", "enable_secure_boot"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data_name", "id"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data_name", "image"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data_name", "keys.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data_name", "name"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data_name", "network_attachments.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data_name", "primary_network_attachment.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data_name", "profile"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data_name", "resource_group"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data_name", "vpc"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data_name", "zone"), + ), + }, + }, + }) +} func TestAccIBMISInstanceTemplate_dataconcom(t *testing.T) { randInt := acctest.RandIntRange(600, 700) publicKey := strings.TrimSpace(` @@ -192,6 +247,16 @@ func testAccCheckIBMISInstanceTemplateDConfig(vpcName, subnetName, sshKeyName, p } `) } +func testAccCheckIBMISInstanceTemplateDatasourceClusterConfig(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { + return fmt.Sprintf(` + data "ibm_is_instance_template" "instance_template_data_name" { + name = "eu-de-test-cluster-it" + } + data "ibm_is_instance_template" "instance_template_data_identifier" { + identifier = "02c7-4a2d29da-429a-4355-9354-31af7c2e6627" + } + `) +} func testAccCheckIBMISInstanceTemplateDconcomConfig(vpcName, subnetName, sshKeyName, publicKey, templateName, ccmode string, esb bool) string { return testAccCheckIBMISInstanceTemplateConComConfig(vpcName, subnetName, sshKeyName, publicKey, templateName, ccmode, esb) + fmt.Sprintf(` data "ibm_is_instance_template" "instance_template_data" { diff --git a/ibm/service/vpc/data_source_ibm_is_instance_templates.go b/ibm/service/vpc/data_source_ibm_is_instance_templates.go index e2cfe87374..890c3df1e6 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_templates.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_templates.go @@ -4,6 +4,7 @@ package vpc import ( + "fmt" "reflect" "time" @@ -97,6 +98,103 @@ func DataSourceIBMISInstanceTemplates() *schema.Resource { Type: schema.TypeString, Computed: true, }, + // cluster changes + "cluster_network_attachments": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The cluster network attachments to create for this virtual server instance. A cluster network attachment represents a device that is connected to a cluster network. The number of network attachments must match one of the values from the instance profile's `cluster_network_attachment_count` before the instance can be started.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cluster_network_interface": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A cluster network interface for the instance cluster network attachment. This can bespecified using an existing cluster network interface that does not already have a `target`,or a prototype object for a new cluster network interface.This instance must reside in the same VPC as the specified cluster network interface. Thecluster network interface must reside in the same cluster network as the`cluster_network_interface` of any other `cluster_network_attachments` for this instance.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this cluster network interface will be automatically deleted when `target` is deleted.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network interface. The name must not be used by another interface in the cluster network. Names beginning with `ibm-` are reserved for provider-owned resources, and are not allowed. If unspecified, the name will be a hyphenated list of randomly-selected words.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The primary IP address to bind to the cluster network interface. May be eithera cluster network subnet reserved IP identity, or a cluster network subnet reserved IPprototype object which will be used to create a new cluster network subnet reserved IP.If a cluster network subnet reserved IP identity is provided, the specified clusternetwork subnet reserved IP must be unbound.If a cluster network subnet reserved IP prototype object with an address is provided,the address must be available on the cluster network interface's cluster networksubnet. If no address is specified, an available address on the cluster network subnetwill be automatically selected and reserved.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network subnet reserved IP.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network subnet reserved IP.", + }, + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.If unspecified, an available address on the subnet will automatically be selected.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this cluster network subnet reserved IP member will be automatically deleted when either `target` is deleted, or the cluster network subnet reserved IP is unbound.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network subnet reserved IP. The name must not be used by another reserved IP in the cluster network subnet. Names starting with `ibm-` are reserved for provider-owned resources, and are not allowed. If unspecified, the name will be a hyphenated list of randomly-selected words.", + }, + }, + }, + }, + "subnet": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The associated cluster network subnet. Required if `primary_ip` does not specify acluster network subnet reserved IP identity.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network subnet.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network subnet.", + }, + }, + }, + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network interface.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network interface.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network attachment. Names must be unique within the instance the cluster network attachment resides in. If unspecified, the name will be a hyphenated list of randomly-selected words. Names starting with `ibm-` are reserved for provider-owned resources, and are not allowed.", + }, + }, + }, + }, "confidential_compute_mode": &schema.Schema{ Type: schema.TypeString, Computed: true, @@ -925,7 +1023,17 @@ func dataSourceIBMISInstanceTemplatesRead(d *schema.ResourceData, meta interface } template["confidential_compute_mode"] = instance.ConfidentialComputeMode - + if instance.ClusterNetworkAttachments != nil { + clusterNetworkAttachments := []map[string]interface{}{} + for _, clusterNetworkAttachmentsItem := range instance.ClusterNetworkAttachments { + clusterNetworkAttachmentsItemMap, err := DataSourceIBMIsInstanceTemplatesInstanceClusterNetworkAttachmentPrototypeInstanceContextToMap(&clusterNetworkAttachmentsItem) // #nosec G601 + if err != nil { + return err + } + clusterNetworkAttachments = append(clusterNetworkAttachments, clusterNetworkAttachmentsItemMap) + } + template["cluster_network_attachments"] = clusterNetworkAttachments + } template["enable_secure_boot"] = instance.EnableSecureBoot if instance.MetadataService != nil { @@ -1232,3 +1340,220 @@ func dataSourceInstanceTemplateCollectionTemplatesPlacementTargetToMap(placement return placementTargetMap } + +func DataSourceIBMIsInstanceTemplatesInstanceClusterNetworkAttachmentPrototypeInstanceContextToMap(model *vpcv1.InstanceClusterNetworkAttachmentPrototypeInstanceContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + clusterNetworkInterfaceMap, err := DataSourceIBMIsInstanceTemplatesInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceToMap(model.ClusterNetworkInterface) + if err != nil { + return modelMap, err + } + modelMap["cluster_network_interface"] = []map[string]interface{}{clusterNetworkInterfaceMap} + if model.Name != nil { + modelMap["name"] = *model.Name + } + return modelMap, nil +} + +func DataSourceIBMIsInstanceTemplatesInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceToMap(model vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceInstanceClusterNetworkInterfacePrototypeInstanceClusterNetworkAttachment); ok { + return DataSourceIBMIsInstanceTemplatesInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceInstanceClusterNetworkInterfacePrototypeInstanceClusterNetworkAttachmentToMap(model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceInstanceClusterNetworkInterfacePrototypeInstanceClusterNetworkAttachment)) + } else if _, ok := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentity); ok { + return DataSourceIBMIsInstanceTemplatesInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityToMap(model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentity)) + } else if _, ok := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterface); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterface) + if model.AutoDelete != nil { + modelMap["auto_delete"] = *model.AutoDelete + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.PrimaryIP != nil { + primaryIPMap, err := DataSourceIBMIsInstanceTemplatesClusterNetworkInterfacePrimaryIPPrototypeToMap(model.PrimaryIP) + if err != nil { + return modelMap, err + } + modelMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + } + if model.Subnet != nil { + subnetMap, err := DataSourceIBMIsInstanceTemplatesClusterNetworkSubnetIdentityToMap(model.Subnet) + if err != nil { + return modelMap, err + } + modelMap["subnet"] = []map[string]interface{}{subnetMap} + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceIntf subtype encountered") + } +} + +func DataSourceIBMIsInstanceTemplatesClusterNetworkInterfacePrimaryIPPrototypeToMap(model vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContext); ok { + return DataSourceIBMIsInstanceTemplatesClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextToMap(model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContext)) + } else if _, ok := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContext); ok { + return DataSourceIBMIsInstanceTemplatesClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContextToMap(model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContext)) + } else if _, ok := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototype); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototype) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + if model.Address != nil { + modelMap["address"] = *model.Address + } + if model.AutoDelete != nil { + modelMap["auto_delete"] = *model.AutoDelete + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeIntf subtype encountered") + } +} + +func DataSourceIBMIsInstanceTemplatesClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextToMap(model vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByID); ok { + return DataSourceIBMIsInstanceTemplatesClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByIDToMap(model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByID)) + } else if _, ok := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHref); ok { + return DataSourceIBMIsInstanceTemplatesClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHrefToMap(model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHref)) + } else if _, ok := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContext); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContext) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextIntf subtype encountered") + } +} + +func DataSourceIBMIsInstanceTemplatesClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByIDToMap(model *vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByID) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = *model.ID + return modelMap, nil +} + +func DataSourceIBMIsInstanceTemplatesClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHrefToMap(model *vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHref) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + return modelMap, nil +} + +func DataSourceIBMIsInstanceTemplatesClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContextToMap(model *vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Address != nil { + modelMap["address"] = *model.Address + } + if model.AutoDelete != nil { + modelMap["auto_delete"] = *model.AutoDelete + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + return modelMap, nil +} + +func DataSourceIBMIsInstanceTemplatesClusterNetworkSubnetIdentityToMap(model vpcv1.ClusterNetworkSubnetIdentityIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.ClusterNetworkSubnetIdentityByID); ok { + return DataSourceIBMIsInstanceTemplatesClusterNetworkSubnetIdentityByIDToMap(model.(*vpcv1.ClusterNetworkSubnetIdentityByID)) + } else if _, ok := model.(*vpcv1.ClusterNetworkSubnetIdentityByHref); ok { + return DataSourceIBMIsInstanceTemplatesClusterNetworkSubnetIdentityByHrefToMap(model.(*vpcv1.ClusterNetworkSubnetIdentityByHref)) + } else if _, ok := model.(*vpcv1.ClusterNetworkSubnetIdentity); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.ClusterNetworkSubnetIdentity) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.ClusterNetworkSubnetIdentityIntf subtype encountered") + } +} + +func DataSourceIBMIsInstanceTemplatesClusterNetworkSubnetIdentityByIDToMap(model *vpcv1.ClusterNetworkSubnetIdentityByID) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = *model.ID + return modelMap, nil +} + +func DataSourceIBMIsInstanceTemplatesClusterNetworkSubnetIdentityByHrefToMap(model *vpcv1.ClusterNetworkSubnetIdentityByHref) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + return modelMap, nil +} + +func DataSourceIBMIsInstanceTemplatesInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceInstanceClusterNetworkInterfacePrototypeInstanceClusterNetworkAttachmentToMap(model *vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceInstanceClusterNetworkInterfacePrototypeInstanceClusterNetworkAttachment) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.AutoDelete != nil { + modelMap["auto_delete"] = *model.AutoDelete + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.PrimaryIP != nil { + primaryIPMap, err := DataSourceIBMIsInstanceTemplatesClusterNetworkInterfacePrimaryIPPrototypeToMap(model.PrimaryIP) + if err != nil { + return modelMap, err + } + modelMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + } + if model.Subnet != nil { + subnetMap, err := DataSourceIBMIsInstanceTemplatesClusterNetworkSubnetIdentityToMap(model.Subnet) + if err != nil { + return modelMap, err + } + modelMap["subnet"] = []map[string]interface{}{subnetMap} + } + return modelMap, nil +} + +func DataSourceIBMIsInstanceTemplatesInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityToMap(model vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByID); ok { + return DataSourceIBMIsInstanceTemplatesInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByIDToMap(model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByID)) + } else if _, ok := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByHref); ok { + return DataSourceIBMIsInstanceTemplatesInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByHrefToMap(model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByHref)) + } else if _, ok := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentity); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentity) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityIntf subtype encountered") + } +} + +func DataSourceIBMIsInstanceTemplatesInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByIDToMap(model *vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByID) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = *model.ID + return modelMap, nil +} + +func DataSourceIBMIsInstanceTemplatesInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByHrefToMap(model *vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByHref) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_templates_test.go b/ibm/service/vpc/data_source_ibm_is_instance_templates_test.go index 12526dd29a..567e44a7c9 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_templates_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_templates_test.go @@ -40,6 +40,60 @@ func TestAccIBMISInstanceTemplates_dataBasic(t *testing.T) { }, }) } +func TestAccIBMISInstanceTemplatesDataSourceCluster(t *testing.T) { + randInt := acctest.RandIntRange(600, 700) + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQ+WiiUR1Jg3oGSmB/2//GJ3XnotriBiGN6t3iwGces6sUsvRkza1t0Mf05DKZxC/zp0WvDTvbit2gTkF9sD37OZSn5aCJk1F5URk/JNPmz25ZogkICFL4OUfhrE3mnyKio6Bk1JIEIypR5PRtGxY9vFDUfruADDLfRi+dGwHF6U9RpvrDRo3FNtI8T0GwvWwFE7bg63vLz65CjYY5XqH9z/YWz/asH6BKumkwiphLGhuGn03+DV6DkIZqr3Oh13UDjMnTdgv1y/Kou5UM3CK1dVsmLRXPEf2KUWUq1EwRfrJXkPOrBwn8to+Yydo57FgrRM9Qw8uzvKmnVxfKW6iG3oSGA0L6ROuCq1lq0MD8ySLd56+d1ftSDaUq+0/Yt9vK3olzVP0/iZobD7chbGqTLMCzL4/CaIUR/UmX08EA0Oh0DdyAdj3UUNETAj3W8gBrV6xLR7fZAJ8roX2BKb4K8Ed3YqzgiY0zgjqvpBYl9xZl0jgVX0qMFaEa6+CeGI8= root@ffd8363b1226 + `) + vpcName := fmt.Sprintf("testvpc%d", randInt) + subnetName := fmt.Sprintf("testsubnet%d", randInt) + templateName := fmt.Sprintf("testtemplate%d", randInt) + sshKeyName := fmt.Sprintf("testsshkey%d", randInt) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceTemplatesDatasourceClusterConfig(vpcName, subnetName, sshKeyName, publicKey, templateName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "id"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.boot_volume_attachment.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.cluster_network_attachments.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.cluster_network_attachments.0.cluster_network_interface.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.crn"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.enable_secure_boot"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.id"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.image"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.keys.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.name"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.network_attachments.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.primary_network_attachment.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.profile"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.resource_group"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.vpc"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.zone"), + ), + }, + }, + }) +} func TestAccIBMISInstanceTemplates_dataconcom(t *testing.T) { randInt := acctest.RandIntRange(600, 700) publicKey := strings.TrimSpace(` @@ -169,6 +223,12 @@ func testAccCheckIBMISInstanceTemplatesDConfig(vpcName, subnetName, sshKeyName, } `) } +func testAccCheckIBMISInstanceTemplatesDatasourceClusterConfig(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { + return fmt.Sprintf(` + data "ibm_is_instance_templates" "instance_templates_data" { + } + `) +} func testAccCheckIBMISInstanceTemplatesDconcomConfig(vpcName, subnetName, sshKeyName, publicKey, templateName, ccmode string, esb bool) string { return testAccCheckIBMISInstanceTemplateConComConfig(vpcName, subnetName, sshKeyName, publicKey, templateName, ccmode, esb) + fmt.Sprintf(` diff --git a/ibm/service/vpc/data_source_ibm_is_instance_test.go b/ibm/service/vpc/data_source_ibm_is_instance_test.go index 325f292f73..0355b59432 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_test.go @@ -50,6 +50,77 @@ func TestAccIBMISInstanceDataSource_basic(t *testing.T) { }, }) } +func TestAccIBMISInstanceDS_BasicCluster(t *testing.T) { + + vpcname := fmt.Sprintf("tfins-vpc-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfins-subnet-%d", acctest.RandIntRange(10, 100)) + sshname := fmt.Sprintf("tfins-ssh-%d", acctest.RandIntRange(10, 100)) + // instanceName := fmt.Sprintf("tfins-name-%d", acctest.RandIntRange(10, 100)) + instanceName := "eu-de-test-cluster-ins" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceDataSourceClusterConfig(vpcname, subnetname, sshname, instanceName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "access_tags.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "availability_policy_host_failure"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "bandwidth"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "boot_volume.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "cluster_network.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "cluster_network_attachments.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "cluster_network_attachments.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "cluster_network_attachments.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "cluster_network_attachments.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "cluster_network_attachments.0.resource_type"), + resource.TestCheckResourceAttr("data.ibm_is_instance.is_instance_instance", "name", instanceName), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "cluster_network_attachments.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "confidential_compute_mode"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "crn"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "disks.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "disks.0.created_at"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "disks.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "disks.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "disks.0.interface_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "disks.0.resource_type"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "disks.0.size"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "enable_secure_boot"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "gpu.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "keys.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "keys.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "keys.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "image"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "lifecycle_reasons.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "lifecycle_state"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "memory"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "metadata_service.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "metadata_service_enabled"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "name"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "network_attachments.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "network_interfaces.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "primary_network_attachment.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "primary_network_interface.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "profile"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "reservation_affinity.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "resource_group"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "status"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "status_reasons.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "status_reasons.0.more_info"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "total_network_bandwidth"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "total_volume_bandwidth"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "vcpu.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "volume_attachments.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "volume_attachments.0.id"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "volume_attachments.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "vpc"), + resource.TestCheckResourceAttrSet("data.ibm_is_instance.is_instance_instance", "zone"), + ), + }, + }, + }) +} func TestAccIBMISInstanceDataSourceWithCatalogOffering(t *testing.T) { @@ -251,6 +322,12 @@ data "ibm_is_instance" "ds_instance" { passphrase = "" }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, instanceName, acc.IsWinImage, acc.InstanceProfileName, acc.ISZoneName) } +func testAccCheckIBMISInstanceDataSourceClusterConfig(vpcname, subnetname, sshname, instanceName string) string { + return fmt.Sprintf(` + data "ibm_is_instance" "is_instance_instance" { + name = "eu-de-test-cluster-ins" + }`) +} func testAccCheckIBMISInstanceDataSourceConfigWithCatalogOffering(vpcname, subnetname, sshname, instanceName, planCrn, versionCrn string) string { return fmt.Sprintf(` diff --git a/ibm/service/vpc/data_source_ibm_is_instances.go b/ibm/service/vpc/data_source_ibm_is_instances.go index 7a26fcf196..29a1185aa9 100644 --- a/ibm/service/vpc/data_source_ibm_is_instances.go +++ b/ibm/service/vpc/data_source_ibm_is_instances.go @@ -62,6 +62,23 @@ func DataSourceIBMISInstances() *schema.Resource { Description: "Instance resource group", }, + // cluster changes + "cluster_network_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Filters the collection to instances with a `cluster_network.id` property matching the specified identifier.", + }, + "cluster_network_crn": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Filters the collection to instances with a `cluster_network.crn` property matching the specified CRN.", + }, + "cluster_network_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Filters the collection to resources with a `cluster_network.name` property matching the exact specified name.", + }, + "dedicated_host_name": { Type: schema.TypeString, Optional: true, @@ -111,6 +128,84 @@ func DataSourceIBMISInstances() *schema.Resource { Computed: true, Description: "The crn for this Instance", }, + // cluster changes + "cluster_network": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, the cluster network that this virtual server instance resides in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this cluster network.", + }, + "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 cluster network.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network. The name must not be used by another cluster network in the region.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "cluster_network_attachments": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The cluster network attachments for this virtual server instance.The cluster network attachments are ordered for consistent instance configuration.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this instance cluster network attachment.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance cluster network attachment.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this instance cluster network attachment. The name is unique across all network attachments for the instance.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, "confidential_compute_mode": &schema.Schema{ Type: schema.TypeString, Computed: true, @@ -1033,6 +1128,35 @@ func DataSourceIBMISInstances() *schema.Resource { }, }, }, + "health_reasons": { + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current health_state (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the reason for this health state.", + }, + "message": { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this health state.", + }, + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this health state.", + }, + }, + }, + }, + "health_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The health of this resource", + }, isInstanceReservation: { Type: schema.TypeList, Computed: true, @@ -1232,6 +1356,17 @@ func instancesList(d *schema.ResourceData, meta interface{}) error { listInstancesOptions := &vpcv1.ListInstancesOptions{} + // cluster changes + if _, ok := d.GetOk("cluster_network_id"); ok { + listInstancesOptions.SetClusterNetworkID(d.Get("cluster_network_id").(string)) + } + if _, ok := d.GetOk("cluster_network_crn"); ok { + listInstancesOptions.SetClusterNetworkCRN(d.Get("cluster_network_crn").(string)) + } + if _, ok := d.GetOk("cluster_network_name"); ok { + listInstancesOptions.SetClusterNetworkName(d.Get("cluster_network_name").(string)) + } + if vpcName != "" { listInstancesOptions.VPCName = &vpcName } @@ -1389,6 +1524,23 @@ func instancesList(d *schema.ResourceData, meta interface{}) error { l[isInstanceCatalogOffering] = catalogList } + if instance.ClusterNetwork != nil { + clusterNetworkMap, err := DataSourceIBMIsInstancesClusterNetworkReferenceToMap(instance.ClusterNetwork) + if err != nil { + return err + } + l["cluster_network"] = []map[string]interface{}{clusterNetworkMap} + } + clusterNetworkAttachments := []map[string]interface{}{} + for _, clusterNetworkAttachmentsItem := range instance.ClusterNetworkAttachments { + clusterNetworkAttachmentsItemMap, err := DataSourceIBMIsInstancesInstanceClusterNetworkAttachmentReferenceToMap(&clusterNetworkAttachmentsItem) // #nosec G601 + if err != nil { + return err + } + clusterNetworkAttachments = append(clusterNetworkAttachments, clusterNetworkAttachmentsItemMap) + } + l["cluster_network_attachments"] = clusterNetworkAttachments + if instance.BootVolumeAttachment != nil { bootVolList := make([]map[string]interface{}, 0) bootVol := map[string]interface{}{} @@ -1613,6 +1765,16 @@ func instancesList(d *schema.ResourceData, meta interface{}) error { if instance.Disks != nil { l[isInstanceDisks] = dataSourceInstanceFlattenDisks(instance.Disks) } + if instance.HealthReasons != nil { + healthReasonsList := []map[string]interface{}{} + for _, healthReasonsItem := range instance.HealthReasons { + healthReasonsList = append(healthReasonsList, dataSourceInstancesCollectionHealthReasonsToMap(healthReasonsItem)) + } + l["health_reasons"] = healthReasonsList + } + if instance.HealthState != nil { + l["health_state"] = instance.HealthState + } if instance.ReservationAffinity != nil { reservationAffinity := []map[string]interface{}{} reservationAffinityMap := map[string]interface{}{} @@ -1630,7 +1792,7 @@ func instancesList(d *schema.ResourceData, meta interface{}) error { res[isReservationResourceType] = *pool.ResourceType if pool.Deleted != nil { deletedList := []map[string]interface{}{} - deletedMap := dataSourceInstanceReservationDeletedToMap(*pool.Deleted) + deletedMap := dataSourceReservationDeletedToMap(*pool.Deleted) deletedList = append(deletedList, deletedMap) res[isReservationDeleted] = deletedList } @@ -1652,7 +1814,7 @@ func instancesList(d *schema.ResourceData, meta interface{}) error { res[isReservationResourceType] = *instance.Reservation.ResourceType if instance.Reservation.Deleted != nil { deletedList := []map[string]interface{}{} - deletedMap := dataSourceInstanceReservationDeletedToMap(*instance.Reservation.Deleted) + deletedMap := dataSourceReservationDeletedToMap(*instance.Reservation.Deleted) deletedList = append(deletedList, deletedMap) res[isReservationDeleted] = deletedList } @@ -1671,3 +1833,51 @@ func instancesList(d *schema.ResourceData, meta interface{}) error { func dataSourceIBMISInstancesID(d *schema.ResourceData) string { return time.Now().UTC().String() } + +func DataSourceIBMIsInstancesClusterNetworkReferenceToMap(model *vpcv1.ClusterNetworkReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = *model.CRN + if model.Deleted != nil { + deletedMap, err := DataSourceIBMIsInstancesDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsInstancesInstanceClusterNetworkAttachmentReferenceToMap(model *vpcv1.InstanceClusterNetworkAttachmentReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["id"] = *model.ID + modelMap["name"] = *model.Name + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func DataSourceIBMIsInstancesDeletedToMap(model *vpcv1.Deleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = *model.MoreInfo + return modelMap, nil +} + +func dataSourceInstancesCollectionHealthReasonsToMap(statusReasonsItem vpcv1.InstanceHealthReason) (healthReasonsMap map[string]interface{}) { + healthReasonsMap = map[string]interface{}{} + + if statusReasonsItem.Code != nil { + healthReasonsMap["code"] = statusReasonsItem.Code + } + if statusReasonsItem.Message != nil { + healthReasonsMap["message"] = statusReasonsItem.Message + } + if statusReasonsItem.MoreInfo != nil { + healthReasonsMap["more_info"] = statusReasonsItem.MoreInfo + } + + return healthReasonsMap +} diff --git a/ibm/service/vpc/data_source_ibm_is_instances_test.go b/ibm/service/vpc/data_source_ibm_is_instances_test.go index ef027ed2c9..b9cbbfe570 100644 --- a/ibm/service/vpc/data_source_ibm_is_instances_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instances_test.go @@ -63,6 +63,62 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE }, }) } +func TestAccIBMISInstancesDS_basicCluster(t *testing.T) { + // var instance string + // vpcname := fmt.Sprintf("tfins-vpc-%d", acctest.RandIntRange(10, 100)) + // subnetname := fmt.Sprintf("tfins-subnet-%d", acctest.RandIntRange(10, 100)) + // publicKey := strings.TrimSpace(` + // ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR + // `) + // sshname := fmt.Sprintf("tfins-ssh-%d", acctest.RandIntRange(10, 100)) + // instanceName := fmt.Sprintf("tfins-name-%d", acctest.RandIntRange(10, 100)) + resName := "data.ibm_is_instances.ds_instances" + // userData := "a" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + // { + // Config: testAccCheckIBMISInstanceConfig(vpcname, subnetname, sshname, publicKey, instanceName, userData), + // Check: resource.ComposeTestCheckFunc( + // testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + // resource.TestCheckResourceAttr( + // "ibm_is_instance.testacc_instance", "name", instanceName), + // resource.TestCheckResourceAttr( + // "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + // ), + // }, + { + Config: testAccCheckIBMISInstancesDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(resName, "instances.0.name"), + resource.TestCheckResourceAttrSet(resName, "instances.0.memory"), + resource.TestCheckResourceAttrSet(resName, "instances.0.status"), + resource.TestCheckResourceAttrSet(resName, "instances.0.resource_group"), + resource.TestCheckResourceAttrSet(resName, "instances.0.vpc"), + resource.TestCheckResourceAttrSet(resName, "instances.0.boot_volume.#"), + resource.TestCheckResourceAttrSet(resName, "instances.0.volume_attachments.#"), + resource.TestCheckResourceAttrSet(resName, "instances.0.primary_network_interface.#"), + resource.TestCheckResourceAttrSet(resName, "instances.0.network_interfaces.#"), + resource.TestCheckResourceAttrSet(resName, "instances.0.profile"), + resource.TestCheckResourceAttrSet(resName, "instances.0.vcpu.#"), + resource.TestCheckResourceAttrSet(resName, "instances.0.zone"), + resource.TestCheckResourceAttrSet(resName, "instances.0.availability_policy_host_failure"), + resource.TestCheckResourceAttrSet(resName, "instances.0.lifecycle_state"), + resource.TestCheckResourceAttr(resName, "instances.0.lifecycle_reasons.#", "0"), + resource.TestCheckResourceAttrSet(resName, "instances.0.vcpu.0.manufacturer"), + resource.TestCheckResourceAttrSet(resName, "instances.0.cluster_network.#"), + resource.TestCheckResourceAttrSet(resName, "instances.0.cluster_network_attachments.#"), + resource.TestCheckResourceAttrSet(resName, "instances.0.cluster_network_attachments.0.href"), + resource.TestCheckResourceAttrSet(resName, "instances.0.cluster_network_attachments.0.id"), + resource.TestCheckResourceAttrSet(resName, "instances.0.cluster_network_attachments.0.name"), + resource.TestCheckResourceAttrSet(resName, "instances.0.cluster_network_attachments.0.resource_type"), + resource.TestCheckResourceAttrSet(resName, "instances.0.cluster_network_attachments.0.resource_type"), + ), + }, + }, + }) +} func TestAccIBMISInstancesDataSourceWithCatalogOffering(t *testing.T) { vpcname := fmt.Sprintf("tfins-vpc-%d", acctest.RandIntRange(10, 100)) diff --git a/ibm/service/vpc/data_source_ibm_is_reservation.go b/ibm/service/vpc/data_source_ibm_is_reservation.go index 66b6d820bb..8c0999028b 100644 --- a/ibm/service/vpc/data_source_ibm_is_reservation.go +++ b/ibm/service/vpc/data_source_ibm_is_reservation.go @@ -310,7 +310,7 @@ func dataSourceIBMIsReservationRead(context context.Context, d *schema.ResourceD if reservation.Profile != nil { profileList := []map[string]interface{}{} profile := reservation.Profile - profileMap := dataSourceReservationProfileToMap(*profile) + profileMap := dataSourceReservationProfileToMap(profile) profileList = append(profileList, profileMap) if err = d.Set("profile", profileList); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting profile: %s", err)) @@ -349,17 +349,23 @@ func dataSourceIBMIsReservationRead(context context.Context, d *schema.ResourceD return nil } -func dataSourceReservationProfileToMap(profileItem vpcv1.ReservationProfile) (profileMap map[string]interface{}) { - profileMap = map[string]interface{}{} +func dataSourceReservationProfileToMap(profileItem vpcv1.ReservationProfileIntf) (profileMap map[string]interface{}) { + var profile *vpcv1.ReservationProfile + if profileItem == nil { + return + } + if profile = profileItem.(*vpcv1.ReservationProfile); profile == nil { + return + } - if profileItem.Href != nil { - profileMap["href"] = profileItem.Href + if profile.Href != nil { + profileMap["href"] = profile.Href } - if profileItem.Name != nil { - profileMap["name"] = profileItem.Name + if profile.Name != nil { + profileMap["name"] = profile.Name } - if profileItem.ResourceType != nil { - profileMap["resource_type"] = profileItem.ResourceType + if profile.ResourceType != nil { + profileMap["resource_type"] = profile.ResourceType } return profileMap } diff --git a/ibm/service/vpc/data_source_ibm_is_reservations.go b/ibm/service/vpc/data_source_ibm_is_reservations.go index 313d7625dd..c773d65e01 100644 --- a/ibm/service/vpc/data_source_ibm_is_reservations.go +++ b/ibm/service/vpc/data_source_ibm_is_reservations.go @@ -341,7 +341,7 @@ func dataSourceReservationCollectionReservationsToMap(reservationsItem vpcv1.Res if reservationsItem.Profile != nil { profileList := []map[string]interface{}{} profile := reservationsItem.Profile - profileMap := dataSourceReservationCollectionReservationsProfileToMap(*profile) + profileMap := dataSourceReservationCollectionReservationsProfileToMap(profile) profileList = append(profileList, profileMap) reservationsMap["profile"] = profileList } @@ -370,17 +370,22 @@ func dataSourceReservationCollectionReservationsToMap(reservationsItem vpcv1.Res return reservationsMap } -func dataSourceReservationCollectionReservationsProfileToMap(profileItem vpcv1.ReservationProfile) (profileMap map[string]interface{}) { - profileMap = map[string]interface{}{} - - if profileItem.Href != nil { - profileMap["href"] = profileItem.Href +func dataSourceReservationCollectionReservationsProfileToMap(profileItem vpcv1.ReservationProfileIntf) (profileMap map[string]interface{}) { + if profileItem == nil { + return + } + var profile *vpcv1.ReservationProfile + if profile = profileItem.(*vpcv1.ReservationProfile); profile == nil { + return + } + if profile.Href != nil { + profileMap["href"] = profile.Href } - if profileItem.Name != nil { - profileMap["name"] = profileItem.Name + if profile.Name != nil { + profileMap["name"] = profile.Name } - if profileItem.ResourceType != nil { - profileMap["resource_type"] = profileItem.ResourceType + if profile.ResourceType != nil { + profileMap["resource_type"] = profile.ResourceType } return profileMap } diff --git a/ibm/service/vpc/data_source_ibm_is_share.go b/ibm/service/vpc/data_source_ibm_is_share.go index 6c321acb33..f27b5480bc 100644 --- a/ibm/service/vpc/data_source_ibm_is_share.go +++ b/ibm/service/vpc/data_source_ibm_is_share.go @@ -552,15 +552,8 @@ func dataSourceIbmIsShareRead(context context.Context, d *schema.ResourceData, m shareItem, response, err := vpcClient.GetShareWithContext(context, getShareOptions) if err != nil { - if response != nil { - if response.StatusCode == 404 { - d.SetId("") - } - log.Printf("[DEBUG] GetShareWithContext failed %s\n%s", err, response) - return nil - } - log.Printf("[DEBUG] GetShareWithContext failed %s\n", err) - return diag.FromErr(err) + log.Printf("[DEBUG] GetShareWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] GetShareWithContext failed %s\n%s", err, response)) } share = shareItem } else if shareName != "" { diff --git a/ibm/service/vpc/data_source_ibm_is_share_test.go b/ibm/service/vpc/data_source_ibm_is_share_test.go index d50e4d4e09..afdcf8a495 100644 --- a/ibm/service/vpc/data_source_ibm_is_share_test.go +++ b/ibm/service/vpc/data_source_ibm_is_share_test.go @@ -5,6 +5,7 @@ package vpc_test import ( "fmt" + "regexp" "testing" acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" @@ -39,6 +40,19 @@ func TestAccIbmIsShareDataSourceBasic(t *testing.T) { }, }) } +func TestAccIbmIsShareDataSource404(t *testing.T) { + shareId := "8843-5fr454ft-f6-4565-9555-5f889f5f3f7777" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmIsShareDataSourceConfig404(shareId), + ExpectError: regexp.MustCompile("GetShareWithContext failed"), + }, + }, + }) +} func TestAccIbmIsShareDataSourceAllArgs(t *testing.T) { shareName := fmt.Sprintf("tf-fs-name-%d", acctest.RandIntRange(10, 100)) @@ -93,6 +107,13 @@ func testAccCheckIbmIsShareDataSourceConfigBasic(name string) string { } `, name, acc.ShareProfileName) } +func testAccCheckIbmIsShareDataSourceConfig404(id string) string { + return fmt.Sprintf(` + data "ibm_is_share" "is_share" { + share = "%s" + } + `, id) +} func testAccCheckIbmIsShareDataSourceConfig(vpcName, shareName string, shareSize int, shareTargetName string) string { return fmt.Sprintf(` diff --git a/ibm/service/vpc/data_source_ibm_is_snapshot.go b/ibm/service/vpc/data_source_ibm_is_snapshot.go index c40e35f64e..57bd4c1b25 100644 --- a/ibm/service/vpc/data_source_ibm_is_snapshot.go +++ b/ibm/service/vpc/data_source_ibm_is_snapshot.go @@ -614,10 +614,7 @@ func snapshotGetByNameOrID(d *schema.ResourceData, meta interface{}, name, id st } snapshot, response, err := sess.GetSnapshot(getSnapshotOptions) if err != nil { - return fmt.Errorf("[ERROR] Error fetching snapshot %s\n%s", err, response) - } - if (response != nil && response.StatusCode == 404) || snapshot == nil { - return fmt.Errorf("[ERROR] No snapshot found with id %s", id) + return fmt.Errorf("[ERROR] Error fetching snapshot with id(%s) %s\n%s", id, err, response) } d.SetId(*snapshot.ID) d.Set(isSnapshotName, *snapshot.Name) diff --git a/ibm/service/vpc/data_source_ibm_is_snapshot_test.go b/ibm/service/vpc/data_source_ibm_is_snapshot_test.go index 776d5dbf90..7d3febec0e 100644 --- a/ibm/service/vpc/data_source_ibm_is_snapshot_test.go +++ b/ibm/service/vpc/data_source_ibm_is_snapshot_test.go @@ -5,6 +5,7 @@ package vpc_test import ( "fmt" + "regexp" "strings" "testing" @@ -47,6 +48,21 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE }, }) } +func TestAccIBMISSnapshotDatasource_404(t *testing.T) { + snpId := "8843-5fr454ft-f6-4565-9555-5f889f5f3f7777" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISSnapshotDestroy, + Steps: []resource.TestStep{ + { + Config: testDSCheckIBMISSnapshotConfig404(snpId), + ExpectError: regexp.MustCompile("Error fetching snapshot with id"), + }, + }, + }) +} func TestAccIBMISSnapshotDatasource_serviceTags(t *testing.T) { var snapshot string snpName := "data.ibm_is_snapshot.ds_snapshot" @@ -241,6 +257,13 @@ func testDSCheckIBMISSnapshotConfig(vpcname, subnetname, sshname, publicKey, vol } `, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, sname, sname) } +func testDSCheckIBMISSnapshotConfig404(sid string) string { + return fmt.Sprintf(` + data "ibm_is_snapshot" "ds_snapshot" { + identifier = "%s" + } +`, sid) +} func testDSCheckIBMISSnapshotClonesBasicConfig(vpcname, subnetname, sshname, publicKey, volname, name, sname string) string { return fmt.Sprintf(` resource "ibm_is_vpc" "testacc_vpc" { diff --git a/ibm/service/vpc/data_source_ibm_is_source_share.go b/ibm/service/vpc/data_source_ibm_is_source_share.go index a25a049fa0..59b38cf396 100644 --- a/ibm/service/vpc/data_source_ibm_is_source_share.go +++ b/ibm/service/vpc/data_source_ibm_is_source_share.go @@ -62,15 +62,8 @@ func dataSourceIbmIsSourceShareRead(context context.Context, d *schema.ResourceD share, response, err := vpcClient.GetShareSourceWithContext(context, getShareSourceOptions) if err != nil { - if response != nil { - if response.StatusCode == 404 { - d.SetId("") - } - log.Printf("[DEBUG] GetShareWithContext failed %s\n%s", err, response) - return nil - } - log.Printf("[DEBUG] GetShareWithContext failed %s\n", err) - return diag.FromErr(fmt.Errorf("[DEBUG] GetShareWithContext failed %s\n", err)) + log.Printf("[DEBUG] GetShareSourceWithContext failed %s\n%s", err, response) + return diag.FromErr(fmt.Errorf("[ERROR] GetShareSourceWithContext failed %s\n%s", err, response)) } d.SetId(*share.ID) diff --git a/ibm/service/vpc/data_source_ibm_is_source_share_test.go b/ibm/service/vpc/data_source_ibm_is_source_share_test.go index 8d8c510d36..5b6f850be8 100644 --- a/ibm/service/vpc/data_source_ibm_is_source_share_test.go +++ b/ibm/service/vpc/data_source_ibm_is_source_share_test.go @@ -5,6 +5,7 @@ package vpc_test import ( "fmt" + "regexp" "testing" acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" @@ -54,3 +55,25 @@ func testAccCheckIbmIsSourceShareDataSourceConfigBasic(vpcname, vpcname1, shareN } `) } +func TestAccIbmIsSourceShareDataSource404(t *testing.T) { + srId := "8843-5fr454ft-f6-4565-9555-5f889f5f3f7777" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmIsSourceShareDataSourceConfig404(srId), + ExpectError: regexp.MustCompile("GetShareSourceWithContext failed"), + }, + }, + }) +} + +func testAccCheckIbmIsSourceShareDataSourceConfig404(srId string) string { + return fmt.Sprintf(` + + data "ibm_is_source_share" "test" { + share_replica = "%s" + } + `, srId) +} diff --git a/ibm/service/vpc/resource_ibm_is_bare_metal_server.go b/ibm/service/vpc/resource_ibm_is_bare_metal_server.go index 766496bdf0..11f794bbbc 100644 --- a/ibm/service/vpc/resource_ibm_is_bare_metal_server.go +++ b/ibm/service/vpc/resource_ibm_is_bare_metal_server.go @@ -1167,6 +1167,148 @@ func ResourceIBMIsBareMetalServer() *schema.Resource { Set: flex.ResourceIBMVPCHash, Description: "List of access management tags", }, + "health_reasons": { + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current health_state (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the reason for this health state.", + }, + "message": { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this health state.", + }, + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this health state.", + }, + }, + }, + }, + "health_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The health of this resource", + }, + isReservation: { + Type: schema.TypeList, + Computed: true, + Description: "The reservation used by this bare metal server", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isReservationId: { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this reservation.", + }, + isReservationCrn: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this reservation.", + }, + isReservationName: { + Type: schema.TypeString, + Computed: true, + Description: "The name for this reservation. The name is unique across all reservations in the region.", + }, + isReservationHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reservation.", + }, + isReservationResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + isReservationDeleted: &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{ + isReservationDeletedMoreInfo: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + }, + }, + }, + isReservationAffinity: { + Type: schema.TypeList, + Optional: true, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "policy": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The reservation affinity policy to use for this bare metal server.", + }, + isReservationAffinityPool: &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "The pool of reservations available for use by this bare metal server.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isReservationId: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The unique identifier for this reservation.", + }, + isReservationCrn: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this reservation.", + }, + isReservationHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reservation.", + }, + isReservationName: { + Type: schema.TypeString, + Computed: true, + Description: "The name for this reservation. The name is unique across all reservations in the region.", + }, + isReservationResourceType: { + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + isReservationDeleted: &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{ + isReservationDeletedMoreInfo: &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about deleted resources.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, }, } } @@ -1292,6 +1434,32 @@ func resourceIBMISBareMetalServerCreate(context context.Context, d *schema.Resou options.Name = &nameStr } + if resAffinity, ok := d.GetOk(isReservationAffinity); ok { + resAff := resAffinity.([]interface{})[0].(map[string]interface{}) + var resAffinity = &vpcv1.BareMetalServerReservationAffinityPrototype{} + policy, ok := resAff["policy"] + policyStr := policy.(string) + if policyStr != "" && ok { + resAffinity.Policy = &policyStr + } + poolIntf, okPool := resAff[isReservationAffinityPool] + if okPool && poolIntf != nil && poolIntf.([]interface{}) != nil && len(poolIntf.([]interface{})) > 0 { + pool := poolIntf.([]interface{})[0].(map[string]interface{}) + id, okId := pool["id"] + if okId { + idStr, ok := id.(string) + if idStr != "" && ok { + var resAffPool = make([]vpcv1.ReservationIdentityIntf, 1) + resAffPool[0] = &vpcv1.ReservationIdentity{ + ID: &idStr, + } + resAffinity.Pool = resAffPool + } + } + } + options.ReservationAffinity = resAffinity + } + if primnicintf, ok := d.GetOk(isBareMetalServerPrimaryNetworkInterface); ok && len(primnicintf.([]interface{})) > 0 { primnic := primnicintf.([]interface{})[0].(map[string]interface{}) subnetintf, _ := primnic[isBareMetalServerNicSubnet] @@ -2130,6 +2298,71 @@ func bareMetalServerGet(context context.Context, d *schema.ResourceData, meta in d.Set(isBareMetalServerPrimaryNetworkInterface, primaryNicList) } + if bms.HealthReasons != nil { + healthReasonsList := make([]map[string]interface{}, 0) + for _, sr := range bms.HealthReasons { + currentSR := map[string]interface{}{} + if sr.Code != nil && sr.Message != nil { + currentSR["code"] = *sr.Code + currentSR["message"] = *sr.Message + if sr.MoreInfo != nil { + currentSR["more_info"] = *sr.Message + } + healthReasonsList = append(healthReasonsList, currentSR) + } + } + d.Set("health_reasons", healthReasonsList) + } + if err = d.Set("health_state", bms.HealthState); err != nil { + return err + } + if bms.ReservationAffinity != nil { + reservationAffinity := []map[string]interface{}{} + reservationAffinityMap := map[string]interface{}{} + + reservationAffinityMap[isReservationAffinityPolicyResp] = bms.ReservationAffinity.Policy + if bms.ReservationAffinity.Pool != nil && len(bms.ReservationAffinity.Pool) > 0 { + poolList := make([]map[string]interface{}, 0) + for _, pool := range bms.ReservationAffinity.Pool { + res := map[string]interface{}{} + + res[isReservationId] = *pool.ID + res[isReservationHref] = *pool.Href + res[isReservationName] = *pool.Name + res[isReservationCrn] = *pool.CRN + res[isReservationResourceType] = *pool.ResourceType + if pool.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceReservationDeletedToMap(*pool.Deleted) + deletedList = append(deletedList, deletedMap) + res[isReservationDeleted] = deletedList + } + poolList = append(poolList, res) + } + reservationAffinityMap[isReservationAffinityPool] = poolList + } + reservationAffinity = append(reservationAffinity, reservationAffinityMap) + d.Set(isReservationAffinity, reservationAffinity) + } + resList := make([]map[string]interface{}, 0) + if bms.Reservation != nil { + res := map[string]interface{}{} + + res[isReservationId] = *bms.Reservation.ID + res[isReservationHref] = *bms.Reservation.Href + res[isReservationName] = *bms.Reservation.Name + res[isReservationCrn] = *bms.Reservation.CRN + res[isReservationResourceType] = *bms.Reservation.ResourceType + if bms.Reservation.Deleted != nil { + deletedList := []map[string]interface{}{} + deletedMap := dataSourceReservationDeletedToMap(*bms.Reservation.Deleted) + deletedList = append(deletedList, deletedMap) + res[isReservationDeleted] = deletedList + } + resList = append(resList, res) + } + d.Set(isReservation, resList) + if !core.IsNil(bms.PrimaryNetworkAttachment) { pnaId := *bms.PrimaryNetworkAttachment.ID getBareMetalServerNetworkAttachment := &vpcv1.GetBareMetalServerNetworkAttachmentOptions{ @@ -3648,8 +3881,49 @@ func bareMetalServerUpdate(context context.Context, d *schema.ResourceData, meta } bmsPatchModel.Name = &nameStr } + resPol := "reservation_affinity.0.policy" + resPool := "reservation_affinity.0.pool" + policyStr := "" + idStr := "" + + if (d.HasChange(resPol) || d.HasChange(resPool)) && !d.IsNewResource() { + flag = true + if resAffinity, ok := d.GetOk(isReservationAffinity); ok { + resAff := resAffinity.([]interface{})[0].(map[string]interface{}) + var resAffinityPatch = &vpcv1.BareMetalServerReservationAffinityPatch{} + policy, ok := resAff["policy"] + policyStr = policy.(string) + if policyStr != "" && ok { + resAffinityPatch.Policy = &policyStr + } + if d.HasChange(resPool) { + poolIntf, okPool := resAff[isReservationAffinityPool] + if okPool && poolIntf != nil && poolIntf.([]interface{}) != nil && len(poolIntf.([]interface{})) > 0 { + pool := poolIntf.([]interface{})[0].(map[string]interface{}) + id, okId := pool["id"] + if okId { + idStr, ok = id.(string) + if idStr != "" && ok { + var resAffPool = make([]vpcv1.ReservationIdentityIntf, 1) + resAffPool[0] = &vpcv1.ReservationIdentity{ + ID: &idStr, + } + resAffinityPatch.Pool = resAffPool + } + } + + } + } + } + } if flag { bmsPatch, err := bmsPatchModel.AsPatch() + //Detaching the reservation from the reserved bare metal server + if policyStr == "disabled" && idStr == "" { + resAffMap := bmsPatch["reservation_affinity"].(map[string]interface{}) + resAffMap["pool"] = nil + bmsPatch["reservation_affinity"] = resAffMap + } if err != nil { return fmt.Errorf("[ERROR] Error calling asPatch for BareMetalServerPatch: %s", err) } @@ -3675,7 +3949,7 @@ func bareMetalServerUpdate(context context.Context, d *schema.ResourceData, meta } if flag || isServerStopped { - isServerStopped, err = resourceStartServerIfStopped(id, "hard", d, context, sess, isServerStopped) + _, err = resourceStartServerIfStopped(id, "hard", d, context, sess, isServerStopped) if err != nil { return err } diff --git a/ibm/service/vpc/resource_ibm_is_bare_metal_server_test.go b/ibm/service/vpc/resource_ibm_is_bare_metal_server_test.go index 3a96f58756..3a5fbadad1 100644 --- a/ibm/service/vpc/resource_ibm_is_bare_metal_server_test.go +++ b/ibm/service/vpc/resource_ibm_is_bare_metal_server_test.go @@ -482,6 +482,77 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE }) } +func TestAccIBMISBareMetalServer_reservation(t *testing.T) { + var server string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-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-sshname-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISBareMetalServerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISBareMetalServerReservationConfig(vpcname, subnetname, sshname, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISBareMetalServerExists("ibm_is_bare_metal_server.testacc_bms", server), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "zone", acc.ISZoneName), + resource.TestCheckResourceAttr( + "ibm_is_bare_metal_server.testacc_bms", "reservation_affinity.0.policy", "manual"), + resource.TestCheckResourceAttrSet( + "ibm_is_bare_metal_server.testacc_bms", "reservation_affinity.0.pool"), + ), + }, + }, + }) +} + +func testAccCheckIBMISBareMetalServerReservationConfig(vpcname, subnetname, sshname, publicKey, name 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_bare_metal_server" "testacc_bms" { + profile = "%s" + name = "%s" + image = "%s" + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + reservation_affinity { + policy = "manual" + pool { + id = "0735-b4a78f50-33bd-44f9-a3ff-4c33f444459d" + } + } + } +`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, acc.IsBareMetalServerProfileName, name, acc.IsBareMetalServerImage, acc.ISZoneName) +} + func testAccCheckIBMISBareMetalServerDestroy(s *terraform.State) error { sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() diff --git a/ibm/service/vpc/resource_ibm_is_cluster_network.go b/ibm/service/vpc/resource_ibm_is_cluster_network.go new file mode 100644 index 0000000000..e475e73330 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_cluster_network.go @@ -0,0 +1,549 @@ +// Copyright IBM Corp. 2024 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/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func ResourceIBMIsClusterNetwork() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMIsClusterNetworkCreate, + ReadContext: resourceIBMIsClusterNetworkRead, + UpdateContext: resourceIBMIsClusterNetworkUpdate, + DeleteContext: resourceIBMIsClusterNetworkDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_cluster_network", "name"), + Description: "The name for this cluster network. The name must not be used by another cluster network in the region.", + }, + "profile": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The globally unique name for this cluster network profile.", + }, + "resource_group": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Description: "The unique identifier for this resource group for this cluster network.", + }, + "subnet_prefixes": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + // Default: [{"cidr":"10.0.0.0/9"}], + Description: "The IP address ranges available for subnets for this cluster network.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allocation_policy": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The allocation policy for this subnet prefix:- `auto`: Subnets created by total count in this cluster network can use this prefix.", + }, + "cidr": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The CIDR block for this prefix.", + }, + }, + }, + }, + "vpc": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Required: true, + ForceNew: true, + Description: "The VPC this cluster network resides in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this VPC.", + }, + "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 VPC.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The unique identifier for this VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this VPC. The name is unique across all VPCs in the region.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "zone": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The globally unique name for the zone this cluster network resides in.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the cluster network was created.", + }, + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this cluster network.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network.", + }, + "lifecycle_reasons": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current `lifecycle_state` (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + "more_info": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the cluster network.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "etag": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func ResourceIBMIsClusterNetworkValidator() *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, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_cluster_network", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMIsClusterNetworkCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network", "create", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + createClusterNetworkOptions := &vpcv1.CreateClusterNetworkOptions{} + + createClusterNetworkOptions.Profile = &vpcv1.ClusterNetworkProfileIdentity{ + Name: core.StringPtr(d.Get("profile").(string)), + } + vpcModel, err := ResourceIBMIsClusterNetworkMapToVPCIdentity(d.Get("vpc.0").(map[string]interface{})) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network", "create", "parse-vpc").GetDiag() + } + createClusterNetworkOptions.SetVPC(vpcModel) + createClusterNetworkOptions.Zone = &vpcv1.ZoneIdentity{ + Name: core.StringPtr(d.Get("zone").(string)), + } + if _, ok := d.GetOk("name"); ok { + createClusterNetworkOptions.SetName(d.Get("name").(string)) + } + if rgOk, ok := d.GetOk("resource_group"); ok { + + createClusterNetworkOptions.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: core.StringPtr(rgOk.(string)), + } + } + if _, ok := d.GetOk("subnet_prefixes"); ok { + var subnetPrefixes []vpcv1.ClusterNetworkSubnetPrefixPrototype + for _, v := range d.Get("subnet_prefixes").([]interface{}) { + value := v.(map[string]interface{}) + subnetPrefixesItem, err := ResourceIBMIsClusterNetworkMapToClusterNetworkSubnetPrefixPrototype(value) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network", "create", "parse-subnet_prefixes").GetDiag() + } + subnetPrefixes = append(subnetPrefixes, *subnetPrefixesItem) + } + createClusterNetworkOptions.SetSubnetPrefixes(subnetPrefixes) + } + + clusterNetwork, _, err := vpcClient.CreateClusterNetworkWithContext(context, createClusterNetworkOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("CreateClusterNetworkWithContext failed: %s", err.Error()), "ibm_is_cluster_network", "create") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(*clusterNetwork.ID) + + return resourceIBMIsClusterNetworkRead(context, d, meta) +} + +func resourceIBMIsClusterNetworkRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + getClusterNetworkOptions := &vpcv1.GetClusterNetworkOptions{} + + getClusterNetworkOptions.SetID(d.Id()) + + clusterNetwork, response, err := vpcClient.GetClusterNetworkWithContext(context, getClusterNetworkOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetClusterNetworkWithContext failed: %s", err.Error()), "ibm_is_cluster_network", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + if !core.IsNil(clusterNetwork.Name) { + if err = d.Set("name", clusterNetwork.Name); err != nil { + err = fmt.Errorf("Error setting name: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network", "read", "set-name").GetDiag() + } + } + if err = d.Set("profile", clusterNetwork.Profile.Name); err != nil { + err = fmt.Errorf("Error setting profile: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network", "read", "set-profile").GetDiag() + } + if !core.IsNil(clusterNetwork.ResourceGroup) { + if err = d.Set("resource_group", clusterNetwork.ResourceGroup.ID); err != nil { + err = fmt.Errorf("Error setting resource_group: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network", "read", "set-resource_group").GetDiag() + } + } + if !core.IsNil(clusterNetwork.SubnetPrefixes) { + subnetPrefixes := []map[string]interface{}{} + for _, subnetPrefixesItem := range clusterNetwork.SubnetPrefixes { + subnetPrefixesItemMap, err := ResourceIBMIsClusterNetworkClusterNetworkSubnetPrefixToMap(&subnetPrefixesItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network", "read", "subnet_prefixes-to-map").GetDiag() + } + subnetPrefixes = append(subnetPrefixes, subnetPrefixesItemMap) + } + if err = d.Set("subnet_prefixes", subnetPrefixes); err != nil { + err = fmt.Errorf("Error setting subnet_prefixes: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network", "read", "set-subnet_prefixes").GetDiag() + } + } + vpcMap, err := ResourceIBMIsClusterNetworkVPCReferenceToMap(clusterNetwork.VPC) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network", "read", "vpc-to-map").GetDiag() + } + if err = d.Set("vpc", []map[string]interface{}{vpcMap}); err != nil { + err = fmt.Errorf("Error setting vpc: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network", "read", "set-vpc").GetDiag() + } + if err = d.Set("zone", clusterNetwork.Zone.Name); err != nil { + err = fmt.Errorf("Error setting zone: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network", "read", "set-zone").GetDiag() + } + if err = d.Set("created_at", flex.DateTimeToString(clusterNetwork.CreatedAt)); err != nil { + err = fmt.Errorf("Error setting created_at: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network", "read", "set-created_at").GetDiag() + } + if err = d.Set("crn", clusterNetwork.CRN); err != nil { + err = fmt.Errorf("Error setting crn: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network", "read", "set-crn").GetDiag() + } + if err = d.Set("href", clusterNetwork.Href); err != nil { + err = fmt.Errorf("Error setting href: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network", "read", "set-href").GetDiag() + } + lifecycleReasons := []map[string]interface{}{} + for _, lifecycleReasonsItem := range clusterNetwork.LifecycleReasons { + lifecycleReasonsItemMap, err := ResourceIBMIsClusterNetworkClusterNetworkLifecycleReasonToMap(&lifecycleReasonsItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network", "read", "lifecycle_reasons-to-map").GetDiag() + } + lifecycleReasons = append(lifecycleReasons, lifecycleReasonsItemMap) + } + if err = d.Set("lifecycle_reasons", lifecycleReasons); err != nil { + err = fmt.Errorf("Error setting lifecycle_reasons: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network", "read", "set-lifecycle_reasons").GetDiag() + } + if err = d.Set("lifecycle_state", clusterNetwork.LifecycleState); err != nil { + err = fmt.Errorf("Error setting lifecycle_state: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network", "read", "set-lifecycle_state").GetDiag() + } + if err = d.Set("resource_type", clusterNetwork.ResourceType); err != nil { + err = fmt.Errorf("Error setting resource_type: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network", "read", "set-resource_type").GetDiag() + } + if err = d.Set("etag", response.Headers.Get("Etag")); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting etag: %s", err), "ibm_is_cluster_network", "read", "set-etag").GetDiag() + } + + return nil +} + +func resourceIBMIsClusterNetworkUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network", "update", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + updateClusterNetworkOptions := &vpcv1.UpdateClusterNetworkOptions{} + + updateClusterNetworkOptions.SetID(d.Id()) + + hasChange := false + + patchVals := &vpcv1.ClusterNetworkPatch{} + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + // updateClusterNetworkOptions.SetIfMatch(d.Get("etag").(string)) + + if hasChange { + updateClusterNetworkOptions.ClusterNetworkPatch = ResourceIBMIsClusterNetworkClusterNetworkPatchAsPatch(patchVals, d) + + _, response, err := vpcClient.UpdateClusterNetworkWithContext(context, updateClusterNetworkOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("UpdateClusterNetworkWithContext failed: %s", err.Error()), "ibm_is_cluster_network", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + if err = d.Set("etag", response.Headers.Get("Etag")); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting etag: %s", err), "ibm_is_cluster_network", "update", "set-etag").GetDiag() + } + } + + return resourceIBMIsClusterNetworkRead(context, d, meta) +} + +func resourceIBMIsClusterNetworkDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network", "delete", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + deleteClusterNetworkOptions := &vpcv1.DeleteClusterNetworkOptions{} + + deleteClusterNetworkOptions.SetID(d.Id()) + + _, _, err = vpcClient.DeleteClusterNetworkWithContext(context, deleteClusterNetworkOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("DeleteClusterNetworkWithContext failed: %s", err.Error()), "ibm_is_cluster_network", "delete") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId("") + + return nil +} + +func ResourceIBMIsClusterNetworkMapToClusterNetworkProfileIdentityByName(modelMap map[string]interface{}) (*vpcv1.ClusterNetworkProfileIdentityByName, error) { + model := &vpcv1.ClusterNetworkProfileIdentityByName{} + model.Name = core.StringPtr(modelMap["name"].(string)) + return model, nil +} + +func ResourceIBMIsClusterNetworkMapToClusterNetworkProfileIdentityByHref(modelMap map[string]interface{}) (*vpcv1.ClusterNetworkProfileIdentityByHref, error) { + model := &vpcv1.ClusterNetworkProfileIdentityByHref{} + model.Href = core.StringPtr(modelMap["href"].(string)) + return model, nil +} + +func ResourceIBMIsClusterNetworkMapToVPCIdentity(modelMap map[string]interface{}) (vpcv1.VPCIdentityIntf, error) { + model := &vpcv1.VPCIdentity{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + return model, nil +} + +func ResourceIBMIsClusterNetworkMapToVPCIdentityByID(modelMap map[string]interface{}) (*vpcv1.VPCIdentityByID, error) { + model := &vpcv1.VPCIdentityByID{} + model.ID = core.StringPtr(modelMap["id"].(string)) + return model, nil +} + +func ResourceIBMIsClusterNetworkMapToVPCIdentityByCRN(modelMap map[string]interface{}) (*vpcv1.VPCIdentityByCRN, error) { + model := &vpcv1.VPCIdentityByCRN{} + model.CRN = core.StringPtr(modelMap["crn"].(string)) + return model, nil +} + +func ResourceIBMIsClusterNetworkMapToVPCIdentityByHref(modelMap map[string]interface{}) (*vpcv1.VPCIdentityByHref, error) { + model := &vpcv1.VPCIdentityByHref{} + model.Href = core.StringPtr(modelMap["href"].(string)) + return model, nil +} + +func ResourceIBMIsClusterNetworkMapToZoneIdentityByName(modelMap map[string]interface{}) (*vpcv1.ZoneIdentityByName, error) { + model := &vpcv1.ZoneIdentityByName{} + model.Name = core.StringPtr(modelMap["name"].(string)) + return model, nil +} + +func ResourceIBMIsClusterNetworkMapToZoneIdentityByHref(modelMap map[string]interface{}) (*vpcv1.ZoneIdentityByHref, error) { + model := &vpcv1.ZoneIdentityByHref{} + model.Href = core.StringPtr(modelMap["href"].(string)) + return model, nil +} + +func ResourceIBMIsClusterNetworkMapToResourceGroupIdentityByID(modelMap map[string]interface{}) (*vpcv1.ResourceGroupIdentityByID, error) { + model := &vpcv1.ResourceGroupIdentityByID{} + model.ID = core.StringPtr(modelMap["id"].(string)) + return model, nil +} + +func ResourceIBMIsClusterNetworkMapToClusterNetworkSubnetPrefixPrototype(modelMap map[string]interface{}) (*vpcv1.ClusterNetworkSubnetPrefixPrototype, error) { + model := &vpcv1.ClusterNetworkSubnetPrefixPrototype{} + if modelMap["cidr"] != nil && modelMap["cidr"].(string) != "" { + model.CIDR = core.StringPtr(modelMap["cidr"].(string)) + } + return model, nil +} + +func ResourceIBMIsClusterNetworkClusterNetworkSubnetPrefixToMap(model *vpcv1.ClusterNetworkSubnetPrefix) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["allocation_policy"] = *model.AllocationPolicy + modelMap["cidr"] = *model.CIDR + return modelMap, nil +} + +func ResourceIBMIsClusterNetworkVPCReferenceToMap(model *vpcv1.VPCReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = *model.CRN + if model.Deleted != nil { + deletedMap, err := ResourceIBMIsClusterNetworkDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func ResourceIBMIsClusterNetworkDeletedToMap(model *vpcv1.Deleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = *model.MoreInfo + return modelMap, nil +} + +func ResourceIBMIsClusterNetworkZoneReferenceToMap(model *vpcv1.ZoneReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["name"] = *model.Name + return modelMap, nil +} + +func ResourceIBMIsClusterNetworkClusterNetworkLifecycleReasonToMap(model *vpcv1.ClusterNetworkLifecycleReason) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["code"] = *model.Code + modelMap["message"] = *model.Message + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} + +func ResourceIBMIsClusterNetworkClusterNetworkPatchAsPatch(patchVals *vpcv1.ClusterNetworkPatch, d *schema.ResourceData) map[string]interface{} { + patch, _ := patchVals.AsPatch() + var path string + + path = "name" + if _, exists := d.GetOk(path); d.HasChange(path) && !exists { + patch["name"] = nil + } + + return patch +} diff --git a/ibm/service/vpc/resource_ibm_is_cluster_network_interface.go b/ibm/service/vpc/resource_ibm_is_cluster_network_interface.go new file mode 100644 index 0000000000..5e24ca7d8f --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_cluster_network_interface.go @@ -0,0 +1,843 @@ +// Copyright IBM Corp. 2024 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/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func ResourceIBMIsClusterNetworkInterface() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMIsClusterNetworkInterfaceCreate, + ReadContext: resourceIBMIsClusterNetworkInterfaceRead, + UpdateContext: resourceIBMIsClusterNetworkInterfaceUpdate, + DeleteContext: resourceIBMIsClusterNetworkInterfaceDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "cluster_network_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_is_cluster_network_interface", "cluster_network_id"), + Description: "The cluster network identifier.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_cluster_network_interface", "name"), + Description: "The name for this cluster network interface. The name is unique across all interfaces in the cluster network.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "The cluster network subnet reserved IP for this cluster network interface.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + ConflictsWith: []string{"primary_ip.0.id", "primary_ip.0.href"}, + Description: "The IP address.If the address is pending allocation, the value will be `0.0.0.0`.This property may [expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) to support IPv6 addresses in the future.", + }, + "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, + Optional: true, + Computed: true, + Description: "The URL for this cluster network subnet reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Computed: true, + ConflictsWith: []string{"primary_ip.0.address", "primary_ip.0.href"}, + Description: "The unique identifier for this cluster network subnet reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{"primary_ip.0.id", "primary_ip.0.href"}, + Description: "The name for this cluster network subnet reserved IP. The name is unique across all reserved IPs in a cluster network subnet.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + ConflictsWith: []string{"primary_ip.0.id", "primary_ip.0.href"}, + Description: "Indicates whether this cluster network subnet reserved IP member will be automatically deleted when either target is deleted, or the cluster network subnet reserved IP is unbound.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "subnet": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + AtLeastOneOf: []string{"subnet", "primary_ip.0.id", "primary_ip.0.href"}, + Optional: true, + Computed: true, + Description: "The associated cluster network subnet. Required if `primary_ip` does not specify a clusternetwork subnet reserved IP identity.", + 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, + Optional: true, + ForceNew: true, + ConflictsWith: []string{"subnet.0.id"}, + Computed: true, + Description: "The URL for this cluster network subnet.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Computed: true, + ConflictsWith: []string{"subnet.0.href"}, + Description: "The unique identifier for this cluster network subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network subnet. The name is unique across all cluster network subnets in the cluster network.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "allow_ip_spoofing": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether source IP spoofing is allowed on this cluster network interface. If `false`, source IP spoofing is prevented on this cluster network interface. If `true`, source IP spoofing is allowed on this cluster network interface.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether this cluster network interface will be automatically deleted when `target` is deleted.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the cluster network interface was created.", + }, + "enable_infrastructure_nat": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + Description: "If `true`:- The VPC infrastructure performs any needed NAT operations.- `floating_ips` must not have more than one floating IP.If `false`:- Packets are passed unchanged to/from the virtual network interface, allowing the workload to perform any needed NAT operations.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network interface.", + }, + "lifecycle_reasons": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current `lifecycle_state` (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + "more_info": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the cluster network interface.", + }, + "mac_address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The MAC address of the cluster network interface. May be absent if`lifecycle_state` is `pending`.", + }, + // "protocol_state_filtering_mode": &schema.Schema{ + // Type: schema.TypeString, + // Computed: true, + // Description: "The protocol state filtering mode used for this cluster network interface.Protocol state filtering monitors each network connection flowing over this cluster network interface, and drops any packets that are invalid based on the current connection state and protocol. See [Protocol state filtering mode](https://cloud.ibm.com/docs/vpc?topic=vpc-vni-about#protocol-state-filtering) for more information.The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + // }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "target": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The target of this cluster network interface.If absent, this cluster network interface is not attached to a target.The resources supported by this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The URL for this instance cluster network attachment.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The unique identifier for this instance cluster network attachment.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The name for this instance cluster network attachment. The name is unique across all network attachments for the instance.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "vpc": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The VPC this cluster network interface resides in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this VPC.", + }, + "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 VPC.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this VPC.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this VPC. The name is unique across all VPCs in the region.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "zone": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The zone this cluster network interface resides in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this zone.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this zone.", + }, + }, + }, + }, + "cluster_network_interface_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network interface.", + }, + "etag": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func ResourceIBMIsClusterNetworkInterfaceValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster_network_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[-0-9a-z_]+$`, + MinValueLength: 1, + MaxValueLength: 64, + }, + 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, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_cluster_network_interface", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMIsClusterNetworkInterfaceCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "create", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + createClusterNetworkInterfaceOptions := &vpcv1.CreateClusterNetworkInterfaceOptions{} + + createClusterNetworkInterfaceOptions.SetClusterNetworkID(d.Get("cluster_network_id").(string)) + if _, ok := d.GetOk("name"); ok { + createClusterNetworkInterfaceOptions.SetName(d.Get("name").(string)) + } + if _, ok := d.GetOk("primary_ip"); ok { + primaryIPModel, err := ResourceIBMIsClusterNetworkInterfaceMapToClusterNetworkInterfacePrimaryIPPrototype(d.Get("primary_ip.0").(map[string]interface{})) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "create", "parse-primary_ip").GetDiag() + } + createClusterNetworkInterfaceOptions.SetPrimaryIP(primaryIPModel) + } + if _, ok := d.GetOk("subnet"); ok { + subnetModel, err := ResourceIBMIsClusterNetworkInterfaceMapToClusterNetworkSubnetIdentity(d.Get("subnet.0").(map[string]interface{})) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "create", "parse-subnet").GetDiag() + } + createClusterNetworkInterfaceOptions.SetSubnet(subnetModel) + } + + clusterNetworkInterface, _, err := vpcClient.CreateClusterNetworkInterfaceWithContext(context, createClusterNetworkInterfaceOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("CreateClusterNetworkInterfaceWithContext failed: %s", err.Error()), "ibm_is_cluster_network_interface", "create") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(fmt.Sprintf("%s/%s", *createClusterNetworkInterfaceOptions.ClusterNetworkID, *clusterNetworkInterface.ID)) + + return resourceIBMIsClusterNetworkInterfaceRead(context, d, meta) +} + +func resourceIBMIsClusterNetworkInterfaceRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + getClusterNetworkInterfaceOptions := &vpcv1.GetClusterNetworkInterfaceOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "sep-id-parts").GetDiag() + } + + getClusterNetworkInterfaceOptions.SetClusterNetworkID(parts[0]) + getClusterNetworkInterfaceOptions.SetID(parts[1]) + + clusterNetworkInterface, response, err := vpcClient.GetClusterNetworkInterfaceWithContext(context, getClusterNetworkInterfaceOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetClusterNetworkInterfaceWithContext failed: %s", err.Error()), "ibm_is_cluster_network_interface", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + if !core.IsNil(clusterNetworkInterface.Name) { + if err = d.Set("name", clusterNetworkInterface.Name); err != nil { + err = fmt.Errorf("Error setting name: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "set-name").GetDiag() + } + } + if !core.IsNil(clusterNetworkInterface.PrimaryIP) { + primaryIPMap, err := ResourceIBMIsClusterNetworkInterfaceClusterNetworkSubnetReservedIPReferenceToMap(clusterNetworkInterface.PrimaryIP) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "primary_ip-to-map").GetDiag() + } + if err = d.Set("primary_ip", []map[string]interface{}{primaryIPMap}); err != nil { + err = fmt.Errorf("Error setting primary_ip: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "set-primary_ip").GetDiag() + } + } + if !core.IsNil(clusterNetworkInterface.Subnet) { + subnetMap, err := ResourceIBMIsClusterNetworkInterfaceClusterNetworkSubnetReferenceToMap(clusterNetworkInterface.Subnet) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "subnet-to-map").GetDiag() + } + if err = d.Set("subnet", []map[string]interface{}{subnetMap}); err != nil { + err = fmt.Errorf("Error setting subnet: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "set-subnet").GetDiag() + } + } + if err = d.Set("allow_ip_spoofing", clusterNetworkInterface.AllowIPSpoofing); err != nil { + err = fmt.Errorf("Error setting allow_ip_spoofing: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "set-allow_ip_spoofing").GetDiag() + } + if err = d.Set("auto_delete", clusterNetworkInterface.AutoDelete); err != nil { + err = fmt.Errorf("Error setting auto_delete: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "set-auto_delete").GetDiag() + } + if err = d.Set("created_at", flex.DateTimeToString(clusterNetworkInterface.CreatedAt)); err != nil { + err = fmt.Errorf("Error setting created_at: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "set-created_at").GetDiag() + } + if err = d.Set("enable_infrastructure_nat", clusterNetworkInterface.EnableInfrastructureNat); err != nil { + err = fmt.Errorf("Error setting enable_infrastructure_nat: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "set-enable_infrastructure_nat").GetDiag() + } + if err = d.Set("href", clusterNetworkInterface.Href); err != nil { + err = fmt.Errorf("Error setting href: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "set-href").GetDiag() + } + lifecycleReasons := []map[string]interface{}{} + for _, lifecycleReasonsItem := range clusterNetworkInterface.LifecycleReasons { + lifecycleReasonsItemMap, err := ResourceIBMIsClusterNetworkInterfaceClusterNetworkInterfaceLifecycleReasonToMap(&lifecycleReasonsItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "lifecycle_reasons-to-map").GetDiag() + } + lifecycleReasons = append(lifecycleReasons, lifecycleReasonsItemMap) + } + if err = d.Set("lifecycle_reasons", lifecycleReasons); err != nil { + err = fmt.Errorf("Error setting lifecycle_reasons: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "set-lifecycle_reasons").GetDiag() + } + if err = d.Set("lifecycle_state", clusterNetworkInterface.LifecycleState); err != nil { + err = fmt.Errorf("Error setting lifecycle_state: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "set-lifecycle_state").GetDiag() + } + if !core.IsNil(clusterNetworkInterface.MacAddress) { + if err = d.Set("mac_address", clusterNetworkInterface.MacAddress); err != nil { + err = fmt.Errorf("Error setting mac_address: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "set-mac_address").GetDiag() + } + } + // if !core.IsNil(clusterNetworkInterface.ProtocolStateFilteringMode) { + // if err = d.Set("protocol_state_filtering_mode", clusterNetworkInterface.ProtocolStateFilteringMode); err != nil { + // err = fmt.Errorf("Error setting protocol_state_filtering_mode: %s", err) + // return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "set-protocol_state_filtering_mode").GetDiag() + // } + // } + if err = d.Set("resource_type", clusterNetworkInterface.ResourceType); err != nil { + err = fmt.Errorf("Error setting resource_type: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "set-resource_type").GetDiag() + } + targetMap := make(map[string]interface{}) + if !core.IsNil(clusterNetworkInterface.Target) { + targetMap, err = ResourceIBMIsClusterNetworkInterfaceClusterNetworkInterfaceTargetToMap(clusterNetworkInterface.Target) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "target-to-map").GetDiag() + } + } + if err = d.Set("target", []map[string]interface{}{targetMap}); err != nil { + err = fmt.Errorf("Error setting target: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "set-target").GetDiag() + } + vpcMap, err := ResourceIBMIsClusterNetworkInterfaceVPCReferenceToMap(clusterNetworkInterface.VPC) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "vpc-to-map").GetDiag() + } + if err = d.Set("vpc", []map[string]interface{}{vpcMap}); err != nil { + err = fmt.Errorf("Error setting vpc: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "set-vpc").GetDiag() + } + zoneMap, err := ResourceIBMIsClusterNetworkInterfaceZoneReferenceToMap(clusterNetworkInterface.Zone) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "zone-to-map").GetDiag() + } + if err = d.Set("zone", []map[string]interface{}{zoneMap}); err != nil { + err = fmt.Errorf("Error setting zone: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "set-zone").GetDiag() + } + if err = d.Set("cluster_network_interface_id", clusterNetworkInterface.ID); err != nil { + err = fmt.Errorf("Error setting cluster_network_interface_id: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "read", "set-cluster_network_interface_id").GetDiag() + } + if err = d.Set("etag", response.Headers.Get("Etag")); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting etag: %s", err), "ibm_is_cluster_network_interface", "read", "set-etag").GetDiag() + } + + return nil +} + +func resourceIBMIsClusterNetworkInterfaceUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "update", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + updateClusterNetworkInterfaceOptions := &vpcv1.UpdateClusterNetworkInterfaceOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "update", "sep-id-parts").GetDiag() + } + + updateClusterNetworkInterfaceOptions.SetClusterNetworkID(parts[0]) + updateClusterNetworkInterfaceOptions.SetID(parts[1]) + + hasChange := false + + patchVals := &vpcv1.ClusterNetworkInterfacePatch{} + if d.HasChange("cluster_network_id") { + errMsg := fmt.Sprintf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "cluster_network_id") + return flex.DiscriminatedTerraformErrorf(nil, errMsg, "ibm_is_cluster_network_interface", "update", "cluster_network_id-forces-new").GetDiag() + } + if d.HasChange("auto_delete") { + newAutoDelete := d.Get("auto_delete").(bool) + patchVals.AutoDelete = &newAutoDelete + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + // updateClusterNetworkInterfaceOptions.SetIfMatch(d.Get("etag").(string)) + + if hasChange { + // Fields with `nil` values are omitted from the generic map, + // so we need to re-add them to support removing arguments + // in merge-patch operations sent to the service. + updateClusterNetworkInterfaceOptions.ClusterNetworkInterfacePatch = ResourceIBMIsClusterNetworkInterfaceClusterNetworkInterfacePatchAsPatch(patchVals, d) + + _, _, err = vpcClient.UpdateClusterNetworkInterfaceWithContext(context, updateClusterNetworkInterfaceOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("UpdateClusterNetworkInterfaceWithContext failed: %s", err.Error()), "ibm_is_cluster_network_interface", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + } + + return resourceIBMIsClusterNetworkInterfaceRead(context, d, meta) +} + +func resourceIBMIsClusterNetworkInterfaceDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "delete", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + deleteClusterNetworkInterfaceOptions := &vpcv1.DeleteClusterNetworkInterfaceOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_interface", "delete", "sep-id-parts").GetDiag() + } + + deleteClusterNetworkInterfaceOptions.SetClusterNetworkID(parts[0]) + deleteClusterNetworkInterfaceOptions.SetID(parts[1]) + + _, _, err = vpcClient.DeleteClusterNetworkInterfaceWithContext(context, deleteClusterNetworkInterfaceOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("DeleteClusterNetworkInterfaceWithContext failed: %s", err.Error()), "ibm_is_cluster_network_interface", "delete") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId("") + + return nil +} + +func ResourceIBMIsClusterNetworkInterfaceMapToClusterNetworkInterfacePrimaryIPPrototype(modelMap map[string]interface{}) (vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeIntf, error) { + model := &vpcv1.ClusterNetworkInterfacePrimaryIPPrototype{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["href"] != nil && modelMap["href"].(string) != "" { + model.Href = core.StringPtr(modelMap["href"].(string)) + } + if modelMap["address"] != nil && modelMap["address"].(string) != "" { + model.Address = core.StringPtr(modelMap["address"].(string)) + } + if modelMap["auto_delete"] != nil { + model.AutoDelete = core.BoolPtr(modelMap["auto_delete"].(bool)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + return model, nil +} + +func ResourceIBMIsClusterNetworkInterfaceMapToClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContext(modelMap map[string]interface{}) (vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextIntf, error) { + model := &vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContext{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["href"] != nil && modelMap["href"].(string) != "" { + model.Href = core.StringPtr(modelMap["href"].(string)) + } + return model, nil +} + +func ResourceIBMIsClusterNetworkInterfaceMapToClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByID(modelMap map[string]interface{}) (*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByID, error) { + model := &vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByID{} + model.ID = core.StringPtr(modelMap["id"].(string)) + return model, nil +} + +func ResourceIBMIsClusterNetworkInterfaceMapToClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHref(modelMap map[string]interface{}) (*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHref, error) { + model := &vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHref{} + model.Href = core.StringPtr(modelMap["href"].(string)) + return model, nil +} + +func ResourceIBMIsClusterNetworkInterfaceMapToClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContext(modelMap map[string]interface{}) (*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContext, error) { + model := &vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContext{} + if modelMap["address"] != nil && modelMap["address"].(string) != "" { + model.Address = core.StringPtr(modelMap["address"].(string)) + } + if modelMap["auto_delete"] != nil { + model.AutoDelete = core.BoolPtr(modelMap["auto_delete"].(bool)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + return model, nil +} + +func ResourceIBMIsClusterNetworkInterfaceMapToClusterNetworkSubnetIdentity(modelMap map[string]interface{}) (vpcv1.ClusterNetworkSubnetIdentityIntf, error) { + model := &vpcv1.ClusterNetworkSubnetIdentity{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["href"] != nil && modelMap["href"].(string) != "" { + model.Href = core.StringPtr(modelMap["href"].(string)) + } + return model, nil +} + +func ResourceIBMIsClusterNetworkInterfaceMapToClusterNetworkSubnetIdentityByID(modelMap map[string]interface{}) (*vpcv1.ClusterNetworkSubnetIdentityByID, error) { + model := &vpcv1.ClusterNetworkSubnetIdentityByID{} + model.ID = core.StringPtr(modelMap["id"].(string)) + return model, nil +} + +func ResourceIBMIsClusterNetworkInterfaceMapToClusterNetworkSubnetIdentityByHref(modelMap map[string]interface{}) (*vpcv1.ClusterNetworkSubnetIdentityByHref, error) { + model := &vpcv1.ClusterNetworkSubnetIdentityByHref{} + model.Href = core.StringPtr(modelMap["href"].(string)) + return model, nil +} + +func ResourceIBMIsClusterNetworkInterfaceClusterNetworkSubnetReservedIPReferenceToMap(model *vpcv1.ClusterNetworkSubnetReservedIPReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["address"] = *model.Address + if model.Deleted != nil { + deletedMap, err := ResourceIBMIsClusterNetworkInterfaceDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func ResourceIBMIsClusterNetworkInterfaceDeletedToMap(model *vpcv1.Deleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = *model.MoreInfo + return modelMap, nil +} + +func ResourceIBMIsClusterNetworkInterfaceClusterNetworkSubnetReferenceToMap(model *vpcv1.ClusterNetworkSubnetReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := ResourceIBMIsClusterNetworkInterfaceDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func ResourceIBMIsClusterNetworkInterfaceClusterNetworkInterfaceLifecycleReasonToMap(model *vpcv1.ClusterNetworkInterfaceLifecycleReason) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["code"] = *model.Code + modelMap["message"] = *model.Message + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} + +func ResourceIBMIsClusterNetworkInterfaceClusterNetworkInterfaceTargetToMap(model vpcv1.ClusterNetworkInterfaceTargetIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.ClusterNetworkInterfaceTargetInstanceClusterNetworkAttachmentReferenceClusterNetworkInterfaceContext); ok { + return ResourceIBMIsClusterNetworkInterfaceClusterNetworkInterfaceTargetInstanceClusterNetworkAttachmentReferenceClusterNetworkInterfaceContextToMap(model.(*vpcv1.ClusterNetworkInterfaceTargetInstanceClusterNetworkAttachmentReferenceClusterNetworkInterfaceContext)) + } else if _, ok := model.(*vpcv1.ClusterNetworkInterfaceTarget); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.ClusterNetworkInterfaceTarget) + 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.ResourceType != nil { + modelMap["resource_type"] = *model.ResourceType + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.ClusterNetworkInterfaceTargetIntf subtype encountered") + } +} + +func ResourceIBMIsClusterNetworkInterfaceClusterNetworkInterfaceTargetInstanceClusterNetworkAttachmentReferenceClusterNetworkInterfaceContextToMap(model *vpcv1.ClusterNetworkInterfaceTargetInstanceClusterNetworkAttachmentReferenceClusterNetworkInterfaceContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["id"] = *model.ID + modelMap["name"] = *model.Name + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func ResourceIBMIsClusterNetworkInterfaceVPCReferenceToMap(model *vpcv1.VPCReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = *model.CRN + if model.Deleted != nil { + deletedMap, err := ResourceIBMIsClusterNetworkInterfaceDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func ResourceIBMIsClusterNetworkInterfaceZoneReferenceToMap(model *vpcv1.ZoneReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["name"] = *model.Name + return modelMap, nil +} + +func ResourceIBMIsClusterNetworkInterfaceClusterNetworkInterfacePatchAsPatch(patchVals *vpcv1.ClusterNetworkInterfacePatch, d *schema.ResourceData) map[string]interface{} { + patch, _ := patchVals.AsPatch() + var path string + + path = "auto_delete" + if _, exists := d.GetOk(path); d.HasChange(path) && !exists { + patch["auto_delete"] = nil + } + path = "name" + if _, exists := d.GetOk(path); d.HasChange(path) && !exists { + patch["name"] = nil + } + + return patch +} diff --git a/ibm/service/vpc/resource_ibm_is_cluster_network_interface_test.go b/ibm/service/vpc/resource_ibm_is_cluster_network_interface_test.go new file mode 100644 index 0000000000..5f2f712661 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_cluster_network_interface_test.go @@ -0,0 +1,197 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_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/vpc-go-sdk/vpcv1" +) + +func TestAccIBMIsClusterNetworkInterfaceBasic(t *testing.T) { + var conf vpcv1.ClusterNetworkInterface + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + clustersubnetname := fmt.Sprintf("tf-clustersubnet-%d", acctest.RandIntRange(10, 100)) + clustersubnetreservedipname := fmt.Sprintf("tf-clustersubnet-reservedip-%d", acctest.RandIntRange(10, 100)) + clusterinterfacename := fmt.Sprintf("tf-clusterinterface-%d", acctest.RandIntRange(10, 100)) + clusterinterfacenameupdated := fmt.Sprintf("tf-clusterinterfaceupdated-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsClusterNetworkInterfaceDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsClusterNetworkInterfaceConfigBasic(vpcname, clustersubnetname, clustersubnetreservedipname, clusterinterfacename), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsClusterNetworkInterfaceExists("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", conf), + resource.TestCheckResourceAttr("ibm_is_vpc.is_vpc", "name", vpcname), + resource.TestCheckResourceAttrSet("ibm_is_vpc.is_vpc", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "allow_ip_spoofing"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "auto_delete"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "cluster_network_id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "cluster_network_interface_id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "enable_infrastructure_nat"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "href"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "lifecycle_state"), + resource.TestCheckResourceAttr("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "lifecycle_state", "stable"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "mac_address"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "resource_type"), + resource.TestCheckResourceAttr("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "resource_type", "cluster_network_interface"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "vpc.#"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "primary_ip.#"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "zone.#"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "subnet.#"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "name"), + resource.TestCheckResourceAttr("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "name", clusterinterfacename), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMIsClusterNetworkInterfaceConfigBasic(vpcname, clustersubnetname, clustersubnetreservedipname, clusterinterfacenameupdated), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsClusterNetworkInterfaceExists("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", conf), + resource.TestCheckResourceAttr("ibm_is_vpc.is_vpc", "name", vpcname), + resource.TestCheckResourceAttrSet("ibm_is_vpc.is_vpc", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "allow_ip_spoofing"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "auto_delete"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "cluster_network_id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "cluster_network_interface_id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "enable_infrastructure_nat"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "href"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "lifecycle_state"), + resource.TestCheckResourceAttr("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "lifecycle_state", "stable"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "mac_address"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "resource_type"), + resource.TestCheckResourceAttr("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "resource_type", "cluster_network_interface"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "vpc.#"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "primary_ip.#"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "zone.#"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "subnet.#"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "name"), + resource.TestCheckResourceAttr("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "name", clusterinterfacenameupdated), + ), + }, + }, + }) +} + +func testAccCheckIBMIsClusterNetworkInterfaceConfigBasic(vpcname, clustersubnetname, clustersubnetreservedipname, clusternetworkinterfacename string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "is_vpc" { + name = "%s" + } + resource "ibm_is_cluster_network" "is_cluster_network_instance" { + profile = "%s" + vpc { + id = ibm_is_vpc.is_vpc.id + } + zone = "%s" + } + resource "ibm_is_cluster_network_subnet" "is_cluster_network_subnet_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + name = "%s" + total_ipv4_address_count = 64 + } + resource "ibm_is_cluster_network_subnet_reserved_ip" "is_cluster_network_subnet_reserved_ip_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + cluster_network_subnet_id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + address = "${replace(ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.ipv4_cidr_block, "0/26", "11")}" + name = "%s" + } + resource "ibm_is_cluster_network_interface" "is_cluster_network_interface_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + name = "%s" + primary_ip { + id = ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance.cluster_network_subnet_reserved_ip_id + } + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + `, vpcname, acc.ISClusterNetworkProfileName, acc.ISZoneName, clustersubnetname, clustersubnetreservedipname, clusternetworkinterfacename) +} + +func testAccCheckIBMIsClusterNetworkInterfaceExists(n string, obj vpcv1.ClusterNetworkInterface) 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 + } + + getClusterNetworkInterfaceOptions := &vpcv1.GetClusterNetworkInterfaceOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getClusterNetworkInterfaceOptions.SetClusterNetworkID(parts[0]) + getClusterNetworkInterfaceOptions.SetID(parts[1]) + + clusterNetworkInterface, _, err := vpcClient.GetClusterNetworkInterface(getClusterNetworkInterfaceOptions) + if err != nil { + return err + } + + obj = *clusterNetworkInterface + return nil + } +} + +func testAccCheckIBMIsClusterNetworkInterfaceDestroy(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_cluster_network_interface" { + continue + } + + getClusterNetworkInterfaceOptions := &vpcv1.GetClusterNetworkInterfaceOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getClusterNetworkInterfaceOptions.SetClusterNetworkID(parts[0]) + getClusterNetworkInterfaceOptions.SetID(parts[1]) + + // Try to find the key + _, response, err := vpcClient.GetClusterNetworkInterface(getClusterNetworkInterfaceOptions) + + if err == nil { + return fmt.Errorf("ClusterNetworkInterface still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for ClusterNetworkInterface (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_cluster_network_subnet.go b/ibm/service/vpc/resource_ibm_is_cluster_network_subnet.go new file mode 100644 index 0000000000..6415090c4f --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_cluster_network_subnet.go @@ -0,0 +1,457 @@ +// Copyright IBM Corp. 2024 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/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func ResourceIBMIsClusterNetworkSubnet() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMIsClusterNetworkSubnetCreate, + ReadContext: resourceIBMIsClusterNetworkSubnetRead, + UpdateContext: resourceIBMIsClusterNetworkSubnetUpdate, + DeleteContext: resourceIBMIsClusterNetworkSubnetDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "cluster_network_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_is_cluster_network_subnet", "cluster_network_id"), + Description: "The cluster network identifier.", + }, + "ip_version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_is_cluster_network_subnet", "ip_version"), + Description: "The IP version for this cluster network subnet.The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "ipv4_cidr_block": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ExactlyOneOf: []string{"ipv4_cidr_block", "total_ipv4_address_count"}, + ValidateFunc: validate.InvokeValidator("ibm_is_cluster_network_subnet", "ipv4_cidr_block"), + Description: "The IPv4 range of this cluster network subnet, expressed in CIDR format.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_cluster_network_subnet", "name"), + Description: "The name for this cluster network subnet. The name is unique across all cluster network subnets in the cluster network.", + }, + "total_ipv4_address_count": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Computed: true, + ForceNew: true, + ExactlyOneOf: []string{"ipv4_cidr_block", "total_ipv4_address_count"}, + Description: "The total number of IPv4 addresses in this cluster network subnet.Note: This is calculated as 2(32 - prefix length). For example, the prefix length `/24` gives:
2(32 - 24) = 28 = 256 addresses.", + }, + "available_ipv4_address_count": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The number of IPv4 addresses in this cluster network subnet that are not in use, and have not been reserved by the user or the provider.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the cluster network subnet was created.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network subnet.", + }, + "lifecycle_reasons": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current `lifecycle_state` (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + "more_info": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the cluster network subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "cluster_network_subnet_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network subnet.", + }, + "etag": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func ResourceIBMIsClusterNetworkSubnetValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster_network_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[-0-9a-z_]+$`, + MinValueLength: 1, + MaxValueLength: 64, + }, + validate.ValidateSchema{ + Identifier: "ip_version", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "ipv4", + Regexp: `^[a-z][a-z0-9]*(_[a-z0-9]+)*$`, + MinValueLength: 1, + MaxValueLength: 128, + }, + validate.ValidateSchema{ + Identifier: "ipv4_cidr_block", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(3[0-2]|[1-2][0-9]|[0-9]))$`, + MinValueLength: 9, + MaxValueLength: 18, + }, + 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, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_cluster_network_subnet", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMIsClusterNetworkSubnetCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet", "create", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + bodyModelMap := map[string]interface{}{} + createClusterNetworkSubnetOptions := &vpcv1.CreateClusterNetworkSubnetOptions{} + + if _, ok := d.GetOk("ip_version"); ok { + bodyModelMap["ip_version"] = d.Get("ip_version") + } + if _, ok := d.GetOk("name"); ok { + bodyModelMap["name"] = d.Get("name") + } + if _, ok := d.GetOk("total_ipv4_address_count"); ok { + bodyModelMap["total_ipv4_address_count"] = d.Get("total_ipv4_address_count") + } + if _, ok := d.GetOk("ipv4_cidr_block"); ok { + bodyModelMap["ipv4_cidr_block"] = d.Get("ipv4_cidr_block") + } + createClusterNetworkSubnetOptions.SetClusterNetworkID(d.Get("cluster_network_id").(string)) + convertedModel, err := ResourceIBMIsClusterNetworkSubnetMapToClusterNetworkSubnetPrototype(bodyModelMap) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet", "create", "parse-request-body").GetDiag() + } + createClusterNetworkSubnetOptions.ClusterNetworkSubnetPrototype = convertedModel + + clusterNetworkSubnet, _, err := vpcClient.CreateClusterNetworkSubnetWithContext(context, createClusterNetworkSubnetOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("CreateClusterNetworkSubnetWithContext failed: %s", err.Error()), "ibm_is_cluster_network_subnet", "create") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(fmt.Sprintf("%s/%s", *createClusterNetworkSubnetOptions.ClusterNetworkID, *clusterNetworkSubnet.ID)) + + return resourceIBMIsClusterNetworkSubnetRead(context, d, meta) +} + +func resourceIBMIsClusterNetworkSubnetRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + getClusterNetworkSubnetOptions := &vpcv1.GetClusterNetworkSubnetOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet", "read", "sep-id-parts").GetDiag() + } + + getClusterNetworkSubnetOptions.SetClusterNetworkID(parts[0]) + getClusterNetworkSubnetOptions.SetID(parts[1]) + + clusterNetworkSubnet, response, err := vpcClient.GetClusterNetworkSubnetWithContext(context, getClusterNetworkSubnetOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetClusterNetworkSubnetWithContext failed: %s", err.Error()), "ibm_is_cluster_network_subnet", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + if !core.IsNil(clusterNetworkSubnet.IPVersion) { + if err = d.Set("ip_version", clusterNetworkSubnet.IPVersion); err != nil { + err = fmt.Errorf("Error setting ip_version: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet", "read", "set-ip_version").GetDiag() + } + } + if !core.IsNil(clusterNetworkSubnet.Ipv4CIDRBlock) { + if err = d.Set("ipv4_cidr_block", clusterNetworkSubnet.Ipv4CIDRBlock); err != nil { + err = fmt.Errorf("Error setting ipv4_cidr_block: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet", "read", "set-ipv4_cidr_block").GetDiag() + } + } + if !core.IsNil(clusterNetworkSubnet.Name) { + if err = d.Set("name", clusterNetworkSubnet.Name); err != nil { + err = fmt.Errorf("Error setting name: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet", "read", "set-name").GetDiag() + } + } + if !core.IsNil(clusterNetworkSubnet.TotalIpv4AddressCount) { + if err = d.Set("total_ipv4_address_count", flex.IntValue(clusterNetworkSubnet.TotalIpv4AddressCount)); err != nil { + err = fmt.Errorf("Error setting total_ipv4_address_count: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet", "read", "set-total_ipv4_address_count").GetDiag() + } + } + if err = d.Set("available_ipv4_address_count", flex.IntValue(clusterNetworkSubnet.AvailableIpv4AddressCount)); err != nil { + err = fmt.Errorf("Error setting available_ipv4_address_count: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet", "read", "set-available_ipv4_address_count").GetDiag() + } + if err = d.Set("created_at", flex.DateTimeToString(clusterNetworkSubnet.CreatedAt)); err != nil { + err = fmt.Errorf("Error setting created_at: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet", "read", "set-created_at").GetDiag() + } + if err = d.Set("href", clusterNetworkSubnet.Href); err != nil { + err = fmt.Errorf("Error setting href: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet", "read", "set-href").GetDiag() + } + lifecycleReasons := []map[string]interface{}{} + for _, lifecycleReasonsItem := range clusterNetworkSubnet.LifecycleReasons { + lifecycleReasonsItemMap, err := ResourceIBMIsClusterNetworkSubnetClusterNetworkSubnetLifecycleReasonToMap(&lifecycleReasonsItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet", "read", "lifecycle_reasons-to-map").GetDiag() + } + lifecycleReasons = append(lifecycleReasons, lifecycleReasonsItemMap) + } + if err = d.Set("lifecycle_reasons", lifecycleReasons); err != nil { + err = fmt.Errorf("Error setting lifecycle_reasons: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet", "read", "set-lifecycle_reasons").GetDiag() + } + if err = d.Set("lifecycle_state", clusterNetworkSubnet.LifecycleState); err != nil { + err = fmt.Errorf("Error setting lifecycle_state: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet", "read", "set-lifecycle_state").GetDiag() + } + if err = d.Set("resource_type", clusterNetworkSubnet.ResourceType); err != nil { + err = fmt.Errorf("Error setting resource_type: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet", "read", "set-resource_type").GetDiag() + } + if err = d.Set("cluster_network_subnet_id", clusterNetworkSubnet.ID); err != nil { + err = fmt.Errorf("Error setting cluster_network_subnet_id: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet", "read", "set-cluster_network_subnet_id").GetDiag() + } + if err = d.Set("etag", response.Headers.Get("Etag")); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting etag: %s", err), "ibm_is_cluster_network_subnet", "read", "set-etag").GetDiag() + } + + return nil +} + +func resourceIBMIsClusterNetworkSubnetUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet", "update", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + updateClusterNetworkSubnetOptions := &vpcv1.UpdateClusterNetworkSubnetOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet", "update", "sep-id-parts").GetDiag() + } + + updateClusterNetworkSubnetOptions.SetClusterNetworkID(parts[0]) + updateClusterNetworkSubnetOptions.SetID(parts[1]) + + hasChange := false + + patchVals := &vpcv1.ClusterNetworkSubnetPatch{} + if d.HasChange("cluster_network_id") { + errMsg := fmt.Sprintf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "cluster_network_id") + return flex.DiscriminatedTerraformErrorf(nil, errMsg, "ibm_is_cluster_network_subnet", "update", "cluster_network_id-forces-new").GetDiag() + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + // updateClusterNetworkSubnetOptions.SetIfMatch(d.Get("etag").(string)) + + if hasChange { + // Fields with `nil` values are omitted from the generic map, + // so we need to re-add them to support removing arguments + // in merge-patch operations sent to the service. + updateClusterNetworkSubnetOptions.ClusterNetworkSubnetPatch = ResourceIBMIsClusterNetworkSubnetClusterNetworkSubnetPatchAsPatch(patchVals, d) + + _, _, err = vpcClient.UpdateClusterNetworkSubnetWithContext(context, updateClusterNetworkSubnetOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("UpdateClusterNetworkSubnetWithContext failed: %s", err.Error()), "ibm_is_cluster_network_subnet", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + } + + return resourceIBMIsClusterNetworkSubnetRead(context, d, meta) +} + +func resourceIBMIsClusterNetworkSubnetDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet", "delete", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + deleteClusterNetworkSubnetOptions := &vpcv1.DeleteClusterNetworkSubnetOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet", "delete", "sep-id-parts").GetDiag() + } + + deleteClusterNetworkSubnetOptions.SetClusterNetworkID(parts[0]) + deleteClusterNetworkSubnetOptions.SetID(parts[1]) + + _, _, err = vpcClient.DeleteClusterNetworkSubnetWithContext(context, deleteClusterNetworkSubnetOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("DeleteClusterNetworkSubnetWithContext failed: %s", err.Error()), "ibm_is_cluster_network_subnet", "delete") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId("") + + return nil +} + +func ResourceIBMIsClusterNetworkSubnetMapToClusterNetworkSubnetPrototype(modelMap map[string]interface{}) (vpcv1.ClusterNetworkSubnetPrototypeIntf, error) { + model := &vpcv1.ClusterNetworkSubnetPrototype{} + if modelMap["ip_version"] != nil && modelMap["ip_version"].(string) != "" { + model.IPVersion = core.StringPtr(modelMap["ip_version"].(string)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["total_ipv4_address_count"] != nil { + model.TotalIpv4AddressCount = core.Int64Ptr(int64(modelMap["total_ipv4_address_count"].(int))) + } + if modelMap["ipv4_cidr_block"] != nil && modelMap["ipv4_cidr_block"].(string) != "" { + model.Ipv4CIDRBlock = core.StringPtr(modelMap["ipv4_cidr_block"].(string)) + } + return model, nil +} + +func ResourceIBMIsClusterNetworkSubnetMapToClusterNetworkSubnetPrototypeClusterNetworkSubnetByTotalCountPrototype(modelMap map[string]interface{}) (*vpcv1.ClusterNetworkSubnetPrototypeClusterNetworkSubnetByTotalCountPrototype, error) { + model := &vpcv1.ClusterNetworkSubnetPrototypeClusterNetworkSubnetByTotalCountPrototype{} + if modelMap["ip_version"] != nil && modelMap["ip_version"].(string) != "" { + model.IPVersion = core.StringPtr(modelMap["ip_version"].(string)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + model.TotalIpv4AddressCount = core.Int64Ptr(int64(modelMap["total_ipv4_address_count"].(int))) + return model, nil +} + +func ResourceIBMIsClusterNetworkSubnetMapToClusterNetworkSubnetPrototypeClusterNetworkSubnetByIPv4CIDRBlockPrototype(modelMap map[string]interface{}) (*vpcv1.ClusterNetworkSubnetPrototypeClusterNetworkSubnetByIPv4CIDRBlockPrototype, error) { + model := &vpcv1.ClusterNetworkSubnetPrototypeClusterNetworkSubnetByIPv4CIDRBlockPrototype{} + if modelMap["ip_version"] != nil && modelMap["ip_version"].(string) != "" { + model.IPVersion = core.StringPtr(modelMap["ip_version"].(string)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + model.Ipv4CIDRBlock = core.StringPtr(modelMap["ipv4_cidr_block"].(string)) + return model, nil +} + +func ResourceIBMIsClusterNetworkSubnetClusterNetworkSubnetLifecycleReasonToMap(model *vpcv1.ClusterNetworkSubnetLifecycleReason) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["code"] = *model.Code + modelMap["message"] = *model.Message + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} + +func ResourceIBMIsClusterNetworkSubnetClusterNetworkSubnetPatchAsPatch(patchVals *vpcv1.ClusterNetworkSubnetPatch, d *schema.ResourceData) map[string]interface{} { + patch, _ := patchVals.AsPatch() + var path string + + path = "name" + if _, exists := d.GetOk(path); d.HasChange(path) && !exists { + patch["name"] = nil + } + + return patch +} diff --git a/ibm/service/vpc/resource_ibm_is_cluster_network_subnet_reserved_ip.go b/ibm/service/vpc/resource_ibm_is_cluster_network_subnet_reserved_ip.go new file mode 100644 index 0000000000..45e227f599 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_cluster_network_subnet_reserved_ip.go @@ -0,0 +1,517 @@ +// Copyright IBM Corp. 2024 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/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func ResourceIBMIsClusterNetworkSubnetReservedIP() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMIsClusterNetworkSubnetReservedIPCreate, + ReadContext: resourceIBMIsClusterNetworkSubnetReservedIPRead, + UpdateContext: resourceIBMIsClusterNetworkSubnetReservedIPUpdate, + DeleteContext: resourceIBMIsClusterNetworkSubnetReservedIPDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "cluster_network_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_is_cluster_network_subnet_reserved_ip", "cluster_network_id"), + Description: "The cluster network identifier.", + }, + "cluster_network_subnet_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_is_cluster_network_subnet_reserved_ip", "cluster_network_subnet_id"), + Description: "The cluster network subnet identifier.", + }, + "address": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_is_cluster_network_subnet_reserved_ip", "address"), + Description: "The IP address.If the address is pending allocation, the value will be `0.0.0.0`.This property may [expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) to support IPv6 addresses in the future.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_cluster_network_subnet_reserved_ip", "name"), + Description: "The name for this cluster network subnet reserved IP. The name is unique across all reserved IPs in a cluster network subnet.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether this cluster network subnet reserved IP member will be automatically deleted when either `target` is deleted, or the cluster network subnet reserved IP is unbound.", + }, + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the cluster network subnet reserved IP was created.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network subnet reserved IP.", + }, + "lifecycle_reasons": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current `lifecycle_state` (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + "more_info": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the cluster network subnet reserved IP.", + }, + "owner": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The owner of the cluster network subnet reserved IPThe enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "target": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The target this cluster network subnet reserved IP is bound to.If absent, this cluster network subnet reserved IP is provider-owned or unbound.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + 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, + Optional: true, + Computed: true, + Description: "The URL for this cluster network interface.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The unique identifier for this cluster network interface.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The name for this cluster network interface. The name is unique across all interfaces in the cluster network.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "cluster_network_subnet_reserved_ip_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network subnet reserved IP.", + }, + "etag": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func ResourceIBMIsClusterNetworkSubnetReservedIPValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "cluster_network_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[-0-9a-z_]+$`, + MinValueLength: 1, + MaxValueLength: 64, + }, + validate.ValidateSchema{ + Identifier: "cluster_network_subnet_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[-0-9a-z_]+$`, + MinValueLength: 1, + MaxValueLength: 64, + }, + validate.ValidateSchema{ + Identifier: "address", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$`, + MinValueLength: 7, + MaxValueLength: 15, + }, + 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, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_cluster_network_subnet_reserved_ip", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMIsClusterNetworkSubnetReservedIPCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet_reserved_ip", "create", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + createClusterNetworkSubnetReservedIPOptions := &vpcv1.CreateClusterNetworkSubnetReservedIPOptions{} + + createClusterNetworkSubnetReservedIPOptions.SetClusterNetworkID(d.Get("cluster_network_id").(string)) + createClusterNetworkSubnetReservedIPOptions.SetClusterNetworkSubnetID(d.Get("cluster_network_subnet_id").(string)) + if _, ok := d.GetOk("address"); ok { + createClusterNetworkSubnetReservedIPOptions.SetAddress(d.Get("address").(string)) + } + if _, ok := d.GetOk("name"); ok { + createClusterNetworkSubnetReservedIPOptions.SetName(d.Get("name").(string)) + } + + clusterNetworkSubnetReservedIP, _, err := vpcClient.CreateClusterNetworkSubnetReservedIPWithContext(context, createClusterNetworkSubnetReservedIPOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("CreateClusterNetworkSubnetReservedIPWithContext failed: %s", err.Error()), "ibm_is_cluster_network_subnet_reserved_ip", "create") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(fmt.Sprintf("%s/%s/%s", *createClusterNetworkSubnetReservedIPOptions.ClusterNetworkID, *createClusterNetworkSubnetReservedIPOptions.ClusterNetworkSubnetID, *clusterNetworkSubnetReservedIP.ID)) + + return resourceIBMIsClusterNetworkSubnetReservedIPRead(context, d, meta) +} + +func resourceIBMIsClusterNetworkSubnetReservedIPRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet_reserved_ip", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + getClusterNetworkSubnetReservedIPOptions := &vpcv1.GetClusterNetworkSubnetReservedIPOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet_reserved_ip", "read", "sep-id-parts").GetDiag() + } + + getClusterNetworkSubnetReservedIPOptions.SetClusterNetworkID(parts[0]) + getClusterNetworkSubnetReservedIPOptions.SetClusterNetworkSubnetID(parts[1]) + getClusterNetworkSubnetReservedIPOptions.SetID(parts[2]) + + clusterNetworkSubnetReservedIP, response, err := vpcClient.GetClusterNetworkSubnetReservedIPWithContext(context, getClusterNetworkSubnetReservedIPOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetClusterNetworkSubnetReservedIPWithContext failed: %s", err.Error()), "ibm_is_cluster_network_subnet_reserved_ip", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + if !core.IsNil(clusterNetworkSubnetReservedIP.Address) { + if err = d.Set("address", clusterNetworkSubnetReservedIP.Address); err != nil { + err = fmt.Errorf("Error setting address: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet_reserved_ip", "read", "set-address").GetDiag() + } + } + if !core.IsNil(clusterNetworkSubnetReservedIP.Name) { + if err = d.Set("name", clusterNetworkSubnetReservedIP.Name); err != nil { + err = fmt.Errorf("Error setting name: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet_reserved_ip", "read", "set-name").GetDiag() + } + } + if err = d.Set("auto_delete", clusterNetworkSubnetReservedIP.AutoDelete); err != nil { + err = fmt.Errorf("Error setting auto_delete: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet_reserved_ip", "read", "set-auto_delete").GetDiag() + } + if err = d.Set("created_at", flex.DateTimeToString(clusterNetworkSubnetReservedIP.CreatedAt)); err != nil { + err = fmt.Errorf("Error setting created_at: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet_reserved_ip", "read", "set-created_at").GetDiag() + } + if err = d.Set("href", clusterNetworkSubnetReservedIP.Href); err != nil { + err = fmt.Errorf("Error setting href: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet_reserved_ip", "read", "set-href").GetDiag() + } + lifecycleReasons := []map[string]interface{}{} + for _, lifecycleReasonsItem := range clusterNetworkSubnetReservedIP.LifecycleReasons { + lifecycleReasonsItemMap, err := ResourceIBMIsClusterNetworkSubnetReservedIPClusterNetworkSubnetReservedIPLifecycleReasonToMap(&lifecycleReasonsItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet_reserved_ip", "read", "lifecycle_reasons-to-map").GetDiag() + } + lifecycleReasons = append(lifecycleReasons, lifecycleReasonsItemMap) + } + if err = d.Set("lifecycle_reasons", lifecycleReasons); err != nil { + err = fmt.Errorf("Error setting lifecycle_reasons: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet_reserved_ip", "read", "set-lifecycle_reasons").GetDiag() + } + if err = d.Set("lifecycle_state", clusterNetworkSubnetReservedIP.LifecycleState); err != nil { + err = fmt.Errorf("Error setting lifecycle_state: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet_reserved_ip", "read", "set-lifecycle_state").GetDiag() + } + if err = d.Set("owner", clusterNetworkSubnetReservedIP.Owner); err != nil { + err = fmt.Errorf("Error setting owner: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet_reserved_ip", "read", "set-owner").GetDiag() + } + if err = d.Set("resource_type", clusterNetworkSubnetReservedIP.ResourceType); err != nil { + err = fmt.Errorf("Error setting resource_type: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet_reserved_ip", "read", "set-resource_type").GetDiag() + } + targetMap := make(map[string]interface{}) + if !core.IsNil(clusterNetworkSubnetReservedIP.Target) { + targetMap, err = ResourceIBMIsClusterNetworkSubnetReservedIPClusterNetworkSubnetReservedIPTargetToMap(clusterNetworkSubnetReservedIP.Target) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet_reserved_ip", "read", "target-to-map").GetDiag() + } + } + if err = d.Set("target", []map[string]interface{}{targetMap}); err != nil { + err = fmt.Errorf("Error setting target: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet_reserved_ip", "read", "set-target").GetDiag() + } + if err = d.Set("cluster_network_subnet_reserved_ip_id", clusterNetworkSubnetReservedIP.ID); err != nil { + err = fmt.Errorf("Error setting cluster_network_subnet_reserved_ip_id: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet_reserved_ip", "read", "set-cluster_network_subnet_reserved_ip_id").GetDiag() + } + if err = d.Set("etag", response.Headers.Get("Etag")); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting etag: %s", err), "ibm_is_cluster_network_subnet_reserved_ip", "read", "set-etag").GetDiag() + } + + return nil +} + +func resourceIBMIsClusterNetworkSubnetReservedIPUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet_reserved_ip", "update", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + updateClusterNetworkSubnetReservedIPOptions := &vpcv1.UpdateClusterNetworkSubnetReservedIPOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet_reserved_ip", "update", "sep-id-parts").GetDiag() + } + + updateClusterNetworkSubnetReservedIPOptions.SetClusterNetworkID(parts[0]) + updateClusterNetworkSubnetReservedIPOptions.SetClusterNetworkSubnetID(parts[1]) + updateClusterNetworkSubnetReservedIPOptions.SetID(parts[2]) + + hasChange := false + + patchVals := &vpcv1.ClusterNetworkSubnetReservedIPPatch{} + if d.HasChange("cluster_network_id") { + errMsg := fmt.Sprintf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "cluster_network_id") + return flex.DiscriminatedTerraformErrorf(nil, errMsg, "ibm_is_cluster_network_subnet_reserved_ip", "update", "cluster_network_id-forces-new").GetDiag() + } + if d.HasChange("cluster_network_subnet_id") { + errMsg := fmt.Sprintf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "cluster_network_subnet_id") + return flex.DiscriminatedTerraformErrorf(nil, errMsg, "ibm_is_cluster_network_subnet_reserved_ip", "update", "cluster_network_subnet_id-forces-new").GetDiag() + } + if d.HasChange("auto_delete") { + newAutoDelete := d.Get("auto_delete").(bool) + patchVals.AutoDelete = &newAutoDelete + hasChange = true + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + // updateClusterNetworkSubnetReservedIPOptions.SetIfMatch(d.Get("etag").(string)) + + if hasChange { + updateClusterNetworkSubnetReservedIPOptions.ClusterNetworkSubnetReservedIPPatch = ResourceIBMIsClusterNetworkSubnetReservedIPClusterNetworkSubnetReservedIPPatchAsPatch(patchVals, d) + + _, _, err = vpcClient.UpdateClusterNetworkSubnetReservedIPWithContext(context, updateClusterNetworkSubnetReservedIPOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("UpdateClusterNetworkSubnetReservedIPWithContext failed: %s", err.Error()), "ibm_is_cluster_network_subnet_reserved_ip", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + } + + return resourceIBMIsClusterNetworkSubnetReservedIPRead(context, d, meta) +} + +func resourceIBMIsClusterNetworkSubnetReservedIPDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet_reserved_ip", "delete", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + deleteClusterNetworkSubnetReservedIPOptions := &vpcv1.DeleteClusterNetworkSubnetReservedIPOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_cluster_network_subnet_reserved_ip", "delete", "sep-id-parts").GetDiag() + } + + deleteClusterNetworkSubnetReservedIPOptions.SetClusterNetworkID(parts[0]) + deleteClusterNetworkSubnetReservedIPOptions.SetClusterNetworkSubnetID(parts[1]) + deleteClusterNetworkSubnetReservedIPOptions.SetID(parts[2]) + + _, _, err = vpcClient.DeleteClusterNetworkSubnetReservedIPWithContext(context, deleteClusterNetworkSubnetReservedIPOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("DeleteClusterNetworkSubnetReservedIPWithContext failed: %s", err.Error()), "ibm_is_cluster_network_subnet_reserved_ip", "delete") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId("") + + return nil +} + +func ResourceIBMIsClusterNetworkSubnetReservedIPClusterNetworkSubnetReservedIPLifecycleReasonToMap(model *vpcv1.ClusterNetworkSubnetReservedIPLifecycleReason) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["code"] = *model.Code + modelMap["message"] = *model.Message + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} + +func ResourceIBMIsClusterNetworkSubnetReservedIPClusterNetworkSubnetReservedIPTargetToMap(model vpcv1.ClusterNetworkSubnetReservedIPTargetIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.ClusterNetworkSubnetReservedIPTargetClusterNetworkInterfaceReferenceClusterNetworkSubnetReservedIPTargetContext); ok { + return ResourceIBMIsClusterNetworkSubnetReservedIPClusterNetworkSubnetReservedIPTargetClusterNetworkInterfaceReferenceClusterNetworkSubnetReservedIPTargetContextToMap(model.(*vpcv1.ClusterNetworkSubnetReservedIPTargetClusterNetworkInterfaceReferenceClusterNetworkSubnetReservedIPTargetContext)) + } else if _, ok := model.(*vpcv1.ClusterNetworkSubnetReservedIPTarget); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.ClusterNetworkSubnetReservedIPTarget) + if model.Deleted != nil { + deletedMap, err := ResourceIBMIsClusterNetworkSubnetReservedIPDeletedToMap(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.ResourceType != nil { + modelMap["resource_type"] = *model.ResourceType + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.ClusterNetworkSubnetReservedIPTargetIntf subtype encountered") + } +} + +func ResourceIBMIsClusterNetworkSubnetReservedIPDeletedToMap(model *vpcv1.Deleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = *model.MoreInfo + return modelMap, nil +} + +func ResourceIBMIsClusterNetworkSubnetReservedIPClusterNetworkSubnetReservedIPTargetClusterNetworkInterfaceReferenceClusterNetworkSubnetReservedIPTargetContextToMap(model *vpcv1.ClusterNetworkSubnetReservedIPTargetClusterNetworkInterfaceReferenceClusterNetworkSubnetReservedIPTargetContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := ResourceIBMIsClusterNetworkSubnetReservedIPDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func ResourceIBMIsClusterNetworkSubnetReservedIPClusterNetworkSubnetReservedIPPatchAsPatch(patchVals *vpcv1.ClusterNetworkSubnetReservedIPPatch, d *schema.ResourceData) map[string]interface{} { + patch, _ := patchVals.AsPatch() + var path string + + path = "auto_delete" + if _, exists := d.GetOk(path); d.HasChange(path) && !exists { + patch["auto_delete"] = nil + } + path = "name" + if _, exists := d.GetOk(path); d.HasChange(path) && !exists { + patch["name"] = nil + } + + return patch +} diff --git a/ibm/service/vpc/resource_ibm_is_cluster_network_subnet_reserved_ip_test.go b/ibm/service/vpc/resource_ibm_is_cluster_network_subnet_reserved_ip_test.go new file mode 100644 index 0000000000..b5a58b1640 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_cluster_network_subnet_reserved_ip_test.go @@ -0,0 +1,152 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_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/vpc-go-sdk/vpcv1" +) + +func TestAccIBMIsClusterNetworkSubnetReservedIPBasic(t *testing.T) { + var conf vpcv1.ClusterNetworkSubnetReservedIP + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + clustersubnetname := fmt.Sprintf("tf-clustersubnet-%d", acctest.RandIntRange(10, 100)) + clustersubnetreservedipname := fmt.Sprintf("tf-clustersubnet-reservedip-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsClusterNetworkSubnetReservedIPDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsClusterNetworkSubnetReservedIPConfigBasic(vpcname, clustersubnetname, clustersubnetreservedipname), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsClusterNetworkSubnetReservedIPExists("ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", conf), + resource.TestCheckResourceAttr("ibm_is_vpc.is_vpc", "name", vpcname), + resource.TestCheckResourceAttrSet("ibm_is_vpc.is_vpc", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "id"), + resource.TestCheckResourceAttr("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "name", clustersubnetname), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "id"), + resource.TestCheckResourceAttr("ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "name", clustersubnetreservedipname), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "address"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "auto_delete"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "cluster_network_id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "cluster_network_subnet_id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "cluster_network_subnet_reserved_ip_id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "href"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "lifecycle_state"), + resource.TestCheckResourceAttr("ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "lifecycle_state", "stable"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "resource_type"), + resource.TestCheckResourceAttr("ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "resource_type", "cluster_network_subnet_reserved_ip"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "owner"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsClusterNetworkSubnetReservedIPConfigBasic(vpcname, clustersubnetname, clustersubnetreservedipname string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "is_vpc" { + name = "%s" + } + resource "ibm_is_cluster_network" "is_cluster_network_instance" { + profile = "%s" + vpc { + id = ibm_is_vpc.is_vpc.id + } + zone = "%s" + } + resource "ibm_is_cluster_network_subnet" "is_cluster_network_subnet_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + name = "%s" + total_ipv4_address_count = 64 + } + resource "ibm_is_cluster_network_subnet_reserved_ip" "is_cluster_network_subnet_reserved_ip_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + cluster_network_subnet_id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + address = "${replace(ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.ipv4_cidr_block, "0/26", "11")}" + name = "%s" + } + `, vpcname, acc.ISClusterNetworkProfileName, acc.ISZoneName, clustersubnetname, clustersubnetreservedipname) +} + +func testAccCheckIBMIsClusterNetworkSubnetReservedIPExists(n string, obj vpcv1.ClusterNetworkSubnetReservedIP) 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 + } + + getClusterNetworkSubnetReservedIPOptions := &vpcv1.GetClusterNetworkSubnetReservedIPOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getClusterNetworkSubnetReservedIPOptions.SetClusterNetworkID(parts[0]) + getClusterNetworkSubnetReservedIPOptions.SetClusterNetworkSubnetID(parts[1]) + getClusterNetworkSubnetReservedIPOptions.SetID(parts[2]) + + clusterNetworkSubnetReservedIP, _, err := vpcClient.GetClusterNetworkSubnetReservedIP(getClusterNetworkSubnetReservedIPOptions) + if err != nil { + return err + } + + obj = *clusterNetworkSubnetReservedIP + return nil + } +} + +func testAccCheckIBMIsClusterNetworkSubnetReservedIPDestroy(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_cluster_network_subnet_reserved_ip" { + continue + } + + getClusterNetworkSubnetReservedIPOptions := &vpcv1.GetClusterNetworkSubnetReservedIPOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getClusterNetworkSubnetReservedIPOptions.SetClusterNetworkID(parts[0]) + getClusterNetworkSubnetReservedIPOptions.SetClusterNetworkSubnetID(parts[1]) + getClusterNetworkSubnetReservedIPOptions.SetID(parts[2]) + + // Try to find the key + _, response, err := vpcClient.GetClusterNetworkSubnetReservedIP(getClusterNetworkSubnetReservedIPOptions) + + if err == nil { + return fmt.Errorf("ClusterNetworkSubnetReservedIP still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for ClusterNetworkSubnetReservedIP (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_cluster_network_subnet_test.go b/ibm/service/vpc/resource_ibm_is_cluster_network_subnet_test.go new file mode 100644 index 0000000000..aca9b5b5b3 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_cluster_network_subnet_test.go @@ -0,0 +1,251 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_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/vpc-go-sdk/vpcv1" +) + +func TestAccIBMIsClusterNetworkSubnetBasic(t *testing.T) { + var conf vpcv1.ClusterNetworkSubnet + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + totalipv4addresscount := int64(64) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsClusterNetworkSubnetDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsClusterNetworkSubnetConfigBasic(vpcname, totalipv4addresscount), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsClusterNetworkSubnetExists("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", conf), + resource.TestCheckResourceAttr("ibm_is_vpc.is_vpc", "name", vpcname), + resource.TestCheckResourceAttrSet("ibm_is_vpc.is_vpc", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "available_ipv4_address_count"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "cluster_network_subnet_id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "href"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "ip_version"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "ipv4_cidr_block"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "lifecycle_state"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "name"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "resource_type"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "total_ipv4_address_count"), + resource.TestCheckResourceAttr("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "total_ipv4_address_count", "64"), + ), + }, + }, + }) +} + +func TestAccIBMIsClusterNetworkSubnetBasicAllArgs(t *testing.T) { + var conf vpcv1.ClusterNetworkSubnet + vpcname := fmt.Sprintf("tf-vpcname-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tf-cluster-subnet1-%d", acctest.RandIntRange(10, 100)) + name1Updated := fmt.Sprintf("tf-cluster-subnet1-updated%d", acctest.RandIntRange(10, 100)) + name2 := fmt.Sprintf("tf-cluster-subnet2-%d", acctest.RandIntRange(10, 100)) + name2Updated := fmt.Sprintf("tf-cluster-subnet2-%d", acctest.RandIntRange(10, 100)) + totalIpv4AddressCount := int64(64) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsClusterNetworkSubnetDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsClusterNetworkSubnetConfig(vpcname, name1, name2, totalIpv4AddressCount), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsClusterNetworkSubnetExists("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", conf), + resource.TestCheckResourceAttr("ibm_is_vpc.is_vpc", "name", vpcname), + resource.TestCheckResourceAttrSet("ibm_is_vpc.is_vpc", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "id"), + resource.TestCheckResourceAttr("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "name", name1), + resource.TestCheckResourceAttr("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "total_ipv4_address_count", "64"), + resource.TestCheckResourceAttr("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "name", name2), + resource.TestCheckResourceAttr("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "ipv4_cidr_block", acc.ISCIDR), + + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "available_ipv4_address_count"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "cluster_network_subnet_id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "href"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "ip_version"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "ipv4_cidr_block"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "lifecycle_state"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "name"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "resource_type"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "total_ipv4_address_count"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "available_ipv4_address_count"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "cluster_network_subnet_id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "href"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "ip_version"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "ipv4_cidr_block"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "lifecycle_state"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "name"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "resource_type"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "total_ipv4_address_count"), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMIsClusterNetworkSubnetConfig(vpcname, name1Updated, name2Updated, totalIpv4AddressCount), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_is_vpc.is_vpc", "name", vpcname), + resource.TestCheckResourceAttrSet("ibm_is_vpc.is_vpc", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "id"), + resource.TestCheckResourceAttr("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "name", name1Updated), + resource.TestCheckResourceAttr("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "total_ipv4_address_count", "64"), + resource.TestCheckResourceAttr("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "name", name2Updated), + resource.TestCheckResourceAttr("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "ipv4_cidr_block", acc.ISCIDR), + + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "available_ipv4_address_count"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "cluster_network_subnet_id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "href"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "ip_version"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "ipv4_cidr_block"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "lifecycle_state"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "name"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "resource_type"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "total_ipv4_address_count"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "available_ipv4_address_count"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "cluster_network_subnet_id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "href"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "ip_version"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "ipv4_cidr_block"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "lifecycle_state"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "name"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "resource_type"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance_cidr", "total_ipv4_address_count"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsClusterNetworkSubnetConfigBasic(vpcname string, totalipv4addresscount int64) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "is_vpc" { + name = "%s" + } + resource "ibm_is_cluster_network" "is_cluster_network_instance" { + profile = "%s" + vpc { + id = ibm_is_vpc.is_vpc.id + } + zone = "%s" + } + resource "ibm_is_cluster_network_subnet" "is_cluster_network_subnet_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + total_ipv4_address_count = %d + } + `, vpcname, acc.ISClusterNetworkProfileName, acc.ISZoneName, totalipv4addresscount) +} + +func testAccCheckIBMIsClusterNetworkSubnetConfig(vpcname, subnetname1, subnetname2 string, totalIpv4AddressCount int64) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "is_vpc" { + name = "%s" + } + resource "ibm_is_cluster_network" "is_cluster_network_instance" { + profile = "%s" + vpc { + id = ibm_is_vpc.is_vpc.id + } + zone = "%s" + } + resource "ibm_is_cluster_network_subnet" "is_cluster_network_subnet_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + name = "%s" + total_ipv4_address_count = %d + } + resource "ibm_is_cluster_network_subnet" "is_cluster_network_subnet_instance_cidr" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + name = "%s" + ipv4_cidr_block = "%s" + } + `, vpcname, acc.ISClusterNetworkProfileName, acc.ISZoneName, subnetname1, totalIpv4AddressCount, subnetname2, acc.ISCIDR) +} + +func testAccCheckIBMIsClusterNetworkSubnetExists(n string, obj vpcv1.ClusterNetworkSubnet) 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 + } + + getClusterNetworkSubnetOptions := &vpcv1.GetClusterNetworkSubnetOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getClusterNetworkSubnetOptions.SetClusterNetworkID(parts[0]) + getClusterNetworkSubnetOptions.SetID(parts[1]) + + clusterNetworkSubnet, _, err := vpcClient.GetClusterNetworkSubnet(getClusterNetworkSubnetOptions) + if err != nil { + return err + } + + obj = *clusterNetworkSubnet + return nil + } +} + +func testAccCheckIBMIsClusterNetworkSubnetDestroy(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_cluster_network_subnet" { + continue + } + + getClusterNetworkSubnetOptions := &vpcv1.GetClusterNetworkSubnetOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getClusterNetworkSubnetOptions.SetClusterNetworkID(parts[0]) + getClusterNetworkSubnetOptions.SetID(parts[1]) + + // Try to find the key + _, response, err := vpcClient.GetClusterNetworkSubnet(getClusterNetworkSubnetOptions) + + if err == nil { + return fmt.Errorf("ClusterNetworkSubnet still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for ClusterNetworkSubnet (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_cluster_network_test.go b/ibm/service/vpc/resource_ibm_is_cluster_network_test.go new file mode 100644 index 0000000000..9828fa4470 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_cluster_network_test.go @@ -0,0 +1,205 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_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/vpc-go-sdk/vpcv1" +) + +func TestAccIBMIsClusterNetworkBasic(t *testing.T) { + var conf vpcv1.ClusterNetwork + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsClusterNetworkDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsClusterNetworkConfigBasic(vpcname), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsClusterNetworkExists("ibm_is_cluster_network.is_cluster_network_instance", conf), + resource.TestCheckResourceAttr("ibm_is_vpc.is_vpc", "name", vpcname), + resource.TestCheckResourceAttrSet("ibm_is_vpc.is_vpc", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "crn"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "href"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "lifecycle_state"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "subnet_prefixes.#"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "vpc.#"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "zone"), + resource.TestCheckResourceAttr("ibm_is_cluster_network.is_cluster_network_instance", "vpc.0.name", vpcname), + resource.TestCheckResourceAttr("ibm_is_cluster_network.is_cluster_network_instance", "profile", acc.ISClusterNetworkProfileName), + resource.TestCheckResourceAttr("ibm_is_cluster_network.is_cluster_network_instance", "lifecycle_state", "stable"), + resource.TestCheckResourceAttr("ibm_is_cluster_network.is_cluster_network_instance", "resource_type", "cluster_network"), + resource.TestCheckResourceAttr("ibm_is_cluster_network.is_cluster_network_instance", "zone", acc.ISZoneName), + ), + }, + }, + }) +} + +func TestAccIBMIsClusterNetworkBasicAllArgs(t *testing.T) { + var conf vpcv1.ClusterNetwork + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + subnetPrefixesCidr := acc.ISClusterNetworkSubnetPrefixesCidr + name := fmt.Sprintf("tf-clusternetwork-%d", acctest.RandIntRange(10, 100)) + nameUpdate := fmt.Sprintf("tf-clusternetwork-updated-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsClusterNetworkDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsClusterNetworkConfig(vpcname, name, subnetPrefixesCidr), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsClusterNetworkExists("ibm_is_cluster_network.is_cluster_network_instance", conf), + resource.TestCheckResourceAttr("ibm_is_cluster_network.is_cluster_network_instance", "name", name), + resource.TestCheckResourceAttr("ibm_is_vpc.is_vpc", "name", vpcname), + resource.TestCheckResourceAttrSet("ibm_is_vpc.is_vpc", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "crn"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "href"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "lifecycle_state"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "subnet_prefixes.#"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "vpc.#"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "zone"), + resource.TestCheckResourceAttr("ibm_is_cluster_network.is_cluster_network_instance", "vpc.0.name", vpcname), + resource.TestCheckResourceAttr("ibm_is_cluster_network.is_cluster_network_instance", "profile", acc.ISClusterNetworkProfileName), + resource.TestCheckResourceAttr("ibm_is_cluster_network.is_cluster_network_instance", "lifecycle_state", "stable"), + resource.TestCheckResourceAttr("ibm_is_cluster_network.is_cluster_network_instance", "resource_type", "cluster_network"), + resource.TestCheckResourceAttr("ibm_is_cluster_network.is_cluster_network_instance", "subnet_prefixes.0.cidr", acc.ISClusterNetworkSubnetPrefixesCidr), + resource.TestCheckResourceAttr("ibm_is_cluster_network.is_cluster_network_instance", "zone", acc.ISZoneName), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMIsClusterNetworkConfig(vpcname, nameUpdate, subnetPrefixesCidr), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_is_cluster_network.is_cluster_network_instance", "name", nameUpdate), + resource.TestCheckResourceAttr("ibm_is_vpc.is_vpc", "name", vpcname), + resource.TestCheckResourceAttrSet("ibm_is_vpc.is_vpc", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "created_at"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "crn"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "href"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "lifecycle_state"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "subnet_prefixes.#"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "vpc.#"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "zone"), + resource.TestCheckResourceAttr("ibm_is_cluster_network.is_cluster_network_instance", "vpc.0.name", vpcname), + resource.TestCheckResourceAttr("ibm_is_cluster_network.is_cluster_network_instance", "profile", acc.ISClusterNetworkProfileName), + resource.TestCheckResourceAttr("ibm_is_cluster_network.is_cluster_network_instance", "lifecycle_state", "stable"), + resource.TestCheckResourceAttr("ibm_is_cluster_network.is_cluster_network_instance", "subnet_prefixes.0.cidr", acc.ISClusterNetworkSubnetPrefixesCidr), + resource.TestCheckResourceAttr("ibm_is_cluster_network.is_cluster_network_instance", "resource_type", "cluster_network"), + resource.TestCheckResourceAttr("ibm_is_cluster_network.is_cluster_network_instance", "zone", acc.ISZoneName), + ), + }, + resource.TestStep{ + ResourceName: "ibm_is_cluster_network.is_cluster_network_instance", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMIsClusterNetworkConfigBasic(vpcname string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "is_vpc" { + name = "%s" + } + resource "ibm_is_cluster_network" "is_cluster_network_instance" { + profile = "%s" + vpc { + id = ibm_is_vpc.is_vpc.id + } + zone = "%s" + } + `, vpcname, acc.ISClusterNetworkProfileName, acc.ISZoneName) +} + +func testAccCheckIBMIsClusterNetworkConfig(vpcname, clusterNetworkName, subnetPrefixesCidr string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "is_vpc" { + name = "%s" + } + resource "ibm_is_cluster_network" "is_cluster_network_instance" { + name = "%s" + profile = "%s" + subnet_prefixes { + cidr = "%s" + } + vpc { + id = ibm_is_vpc.is_vpc.id + } + zone = "%s" + } + `, vpcname, clusterNetworkName, acc.ISClusterNetworkProfileName, subnetPrefixesCidr, acc.ISZoneName) +} + +func testAccCheckIBMIsClusterNetworkExists(n string, obj vpcv1.ClusterNetwork) 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 + } + + getClusterNetworkOptions := &vpcv1.GetClusterNetworkOptions{} + + getClusterNetworkOptions.SetID(rs.Primary.ID) + + clusterNetwork, _, err := vpcClient.GetClusterNetwork(getClusterNetworkOptions) + if err != nil { + return err + } + + obj = *clusterNetwork + return nil + } +} + +func testAccCheckIBMIsClusterNetworkDestroy(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_cluster_network" { + continue + } + + getClusterNetworkOptions := &vpcv1.GetClusterNetworkOptions{} + + getClusterNetworkOptions.SetID(rs.Primary.ID) + + // Try to find the key + _, response, err := vpcClient.GetClusterNetwork(getClusterNetworkOptions) + + if err == nil { + return fmt.Errorf("ClusterNetwork still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for ClusterNetwork (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_instance.go b/ibm/service/vpc/resource_ibm_is_instance.go index cb2e000aa3..bf50974825 100644 --- a/ibm/service/vpc/resource_ibm_is_instance.go +++ b/ibm/service/vpc/resource_ibm_is_instance.go @@ -9,6 +9,7 @@ import ( "fmt" "log" "os" + "reflect" "strings" "time" @@ -215,6 +216,186 @@ func ResourceIBMISInstance() *schema.Resource { Description: "Crn for this Instance", }, + // cluster changes + "cluster_network_attachments": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Description: "The cluster network attachments for this virtual server instance.The cluster network attachments are ordered for consistent instance configuration.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cluster_network_interface": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Required: true, + Description: "A cluster network interface for the instance cluster network attachment. This can bespecified using an existing cluster network interface that does not already have a `target`,or a prototype object for a new cluster network interface.This instance must reside in the same VPC as the specified cluster network interface. Thecluster network interface must reside in the same cluster network as the`cluster_network_interface` of any other `cluster_network_attachments` for this instance.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + DiffSuppressOnRefresh: true, + DiffSuppressFunc: flex.ApplyOnce, + Description: "Indicates whether this cluster network interface will be automatically deleted when `target` is deleted.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The name for this cluster network interface. The name must not be used by another interface in the cluster network. Names beginning with `ibm-` are reserved for provider-owned resources, and are not allowed. If unspecified, the name will be a hyphenated list of randomly-selected words.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "The primary IP address to bind to the cluster network interface. May be eithera cluster network subnet reserved IP identity, or a cluster network subnet reserved IPprototype object which will be used to create a new cluster network subnet reserved IP.If a cluster network subnet reserved IP identity is provided, the specified clusternetwork subnet reserved IP must be unbound.If a cluster network subnet reserved IP prototype object with an address is provided,the address must be available on the cluster network interface's cluster networksubnet. If no address is specified, an available address on the cluster network subnetwill be automatically selected and reserved.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The unique identifier for this cluster network subnet reserved IP.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network subnet reserved IP.", + }, + "address": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.If unspecified, an available address on the subnet will automatically be selected.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + DiffSuppressFunc: flex.ApplyOnce, + Description: "Indicates whether this cluster network subnet reserved IP member will be automatically deleted when either `target` is deleted, or the cluster network subnet reserved IP is unbound.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The name for this cluster network subnet reserved IP. The name must not be used by another reserved IP in the cluster network subnet. Names starting with `ibm-` are reserved for provider-owned resources, and are not allowed. If unspecified, the name will be a hyphenated list of randomly-selected words.", + }, + }, + }, + }, + "subnet": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "The associated cluster network subnet. Required if `primary_ip` does not specify acluster network subnet reserved IP identity.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The unique identifier for this cluster network subnet.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The URL for this cluster network subnet.", + }, + }, + }, + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The unique identifier for this cluster network interface.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this cluster network interface.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The name for this cluster network attachment. Names must be unique within the instance the cluster network attachment resides in. If unspecified, the name will be a hyphenated list of randomly-selected words. Names starting with `ibm-` are reserved for provider-owned resources, and are not allowed.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this instance cluster network attachment.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance cluster network attachment.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "cluster_network": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "If present, the cluster network that this virtual server instance resides in.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this cluster network.", + }, + "deleted": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + 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 cluster network.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network. The name must not be used by another cluster network in the region.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "confidential_compute_mode": &schema.Schema{ Type: schema.TypeString, Optional: true, @@ -542,6 +723,87 @@ func ResourceIBMISInstance() *schema.Resource { }, }, + // volume_prototypes + "volume_prototypes": { + Type: schema.TypeList, + Optional: true, + DiffSuppressFunc: diffSuppressVolumePrototypes, + ConflictsWith: []string{isInstanceVolumes}, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: flex.ApplyOnce, + }, + "delete_volume_on_instance_delete": { + Type: schema.TypeBool, + Optional: true, + }, + "volume_id": { + Type: schema.TypeString, + Computed: true, + }, + "volume_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "volume_crn": { + Type: schema.TypeString, + Computed: true, + }, + "volume_resource_type": { + Type: schema.TypeString, + Computed: true, + }, + "volume_iops": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + Description: "The maximum I/O operations per second (IOPS) for the volume.", + }, + "volume_profile": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The globally unique name for the volume profile to use for this volume.", + }, + "volume_capacity": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + Description: "The capacity of the volume in gigabytes. The specified minimum and maximum capacity values for creating or updating volumes may expand in the future.", + }, + "volume_source_snapshot": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The snapshot from which to clone the volume", + }, + "volume_encryption_key": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource.", + }, + "volume_tags": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_instance_template", "tags")}, + Set: flex.ResourceIBMVPCHash, + Description: "UserTags for the volume instance", + }, + }, + }, + }, + "primary_network_attachment": &schema.Schema{ Type: schema.TypeList, MaxItems: 1, @@ -1230,10 +1492,11 @@ func ResourceIBMISInstance() *schema.Resource { }, isInstanceVolumes: { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "List of volumes", + Type: schema.TypeList, + Optional: true, + ConflictsWith: []string{"volume_prototypes"}, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "List of volumes", }, isInstanceVolAttVolAutoDelete: { Type: schema.TypeBool, @@ -1546,6 +1809,35 @@ func ResourceIBMISInstance() *schema.Resource { }, }, }, + "health_reasons": { + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current health_state (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the reason for this health state.", + }, + "message": { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this health state.", + }, + "more_info": { + Type: schema.TypeString, + Computed: true, + Description: "Link to documentation about the reason for this health state.", + }, + }, + }, + }, + "health_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The health of this resource", + }, isInstanceReservation: { Type: schema.TypeList, Computed: true, @@ -1787,6 +2079,102 @@ func instanceCreateByImage(d *schema.ResourceData, meta interface{}, profile, na ID: &vpcID, }, } + + // cluster changes + if clusterNetworkAttachmentOk, ok := d.GetOk("cluster_network_attachments"); ok { + clusterNetworkAttachmentList := clusterNetworkAttachmentOk.([]interface{}) + if len(clusterNetworkAttachmentList) > 0 { + clusterNetworkAttachments := []vpcv1.InstanceClusterNetworkAttachmentPrototypeInstanceContext{} + for _, clusterNetworkAttachmentsItem := range clusterNetworkAttachmentList { + clusterNetworkAttachmentsItemModel, err := ResourceIBMIsInstanceMapToInstanceClusterNetworkAttachmentPrototypeInstanceContext(clusterNetworkAttachmentsItem.(map[string]interface{})) + if err != nil { + return err + } + clusterNetworkAttachments = append(clusterNetworkAttachments, *clusterNetworkAttachmentsItemModel) + } + instanceproto.ClusterNetworkAttachments = clusterNetworkAttachments + } + } + + // volume_prototypes + if volumeattintf, ok := d.GetOk("volume_prototypes"); ok { + volumeatt := []vpcv1.VolumeAttachmentPrototype{} + for i, _ := range volumeattintf.([]interface{}) { + volumeattItemModel := &vpcv1.VolumeAttachmentPrototype{} + volumeattItemPrototypeModel := &vpcv1.VolumeAttachmentPrototypeVolume{} + if attNameOk, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.name", i)); ok { + attName := attNameOk.(string) + if attName != "" { + volumeattItemModel.Name = &attName + } + } + if vname, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_name", i)); ok { + volName := vname.(string) + if volName != "" { + volumeattItemPrototypeModel.Name = &volName + } + } + if volAutoDelete, ok := d.GetOkExists(fmt.Sprintf("volume_prototypes.%d.delete_volume_on_instance_delete", i)); ok { + volumeattItemModel.DeleteVolumeOnInstanceDelete = core.BoolPtr(volAutoDelete.(bool)) + } + if volIops, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_iops", i)); ok { + if volIops.(int) != 0 { + volumeattItemPrototypeModel.Iops = core.Int64Ptr(int64(volIops.(int))) + } + } + if volCapacity, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_capacity", i)); ok { + if volCapacity != 0 { + volumeattItemPrototypeModel.Capacity = core.Int64Ptr(int64(volCapacity.(int))) + } + } + if volEncKeyOk, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_encryption_key", i)); ok { + volEncKey := volEncKeyOk.(string) + if volEncKey != "" { + volumeattItemPrototypeModel.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ + CRN: &volEncKey, + } + } + } + if volProfileOk, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_profile", i)); ok { + volProfile := volProfileOk.(string) + if volProfile != "" { + volumeattItemPrototypeModel.Profile = &vpcv1.VolumeProfileIdentity{ + Name: &volProfile, + } + } + } + if volRgOk, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_resource_group", i)); ok { + volRg := volRgOk.(string) + if volRg != "" { + volumeattItemPrototypeModel.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &volRg, + } + } + } + if volSnapshotok, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_source_snapshot", i)); ok { + volSnapshot := volSnapshotok.(string) + if volSnapshot != "" { + volumeattItemPrototypeModel.SourceSnapshot = &vpcv1.SnapshotIdentity{ + ID: &volSnapshot, + } + } + } + volTags := d.Get(fmt.Sprintf("volume_prototypes.%d.volume_tags", i)).(*schema.Set) + if volTags != nil && volTags.Len() != 0 { + userTagsArray := make([]string, volTags.Len()) + for i, userTag := range volTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + volumeattItemPrototypeModel.UserTags = userTagsArray + } + + volumeattItemModel.Volume = volumeattItemPrototypeModel + + volumeatt = append(volumeatt, *volumeattItemModel) + } + instanceproto.VolumeAttachments = volumeatt + } if _, ok := d.GetOk("confidential_compute_mode"); ok { instanceproto.ConfidentialComputeMode = core.StringPtr(d.Get("confidential_compute_mode").(string)) } @@ -1933,7 +2321,7 @@ func instanceCreateByImage(d *schema.ResourceData, meta interface{}, profile, na resAffinity.Policy = &policyStr } poolIntf, okPool := resAff[isReservationAffinityPool] - if okPool { + if okPool && poolIntf != nil && poolIntf.([]interface{}) != nil && len(poolIntf.([]interface{})) > 0 { pool := poolIntf.([]interface{})[0].(map[string]interface{}) id, okId := pool["id"] if okId { @@ -2223,6 +2611,100 @@ func instanceCreateByCatalogOffering(d *schema.ResourceData, meta interface{}, p ID: &vpcID, }, } + // cluster changes + if clusterNetworkAttachmentOk, ok := d.GetOk("cluster_network_attachments"); ok { + clusterNetworkAttachmentList := clusterNetworkAttachmentOk.([]interface{}) + if len(clusterNetworkAttachmentList) > 0 { + clusterNetworkAttachments := []vpcv1.InstanceClusterNetworkAttachmentPrototypeInstanceContext{} + for _, clusterNetworkAttachmentsItem := range clusterNetworkAttachmentList { + clusterNetworkAttachmentsItemModel, err := ResourceIBMIsInstanceMapToInstanceClusterNetworkAttachmentPrototypeInstanceContext(clusterNetworkAttachmentsItem.(map[string]interface{})) + if err != nil { + return err + } + clusterNetworkAttachments = append(clusterNetworkAttachments, *clusterNetworkAttachmentsItemModel) + } + instanceproto.ClusterNetworkAttachments = clusterNetworkAttachments + } + } + // volume_prototypes + if volumeattintf, ok := d.GetOk("volume_prototypes"); ok { + volumeatt := []vpcv1.VolumeAttachmentPrototype{} + for i, _ := range volumeattintf.([]interface{}) { + volumeattItemModel := &vpcv1.VolumeAttachmentPrototype{} + volumeattItemPrototypeModel := &vpcv1.VolumeAttachmentPrototypeVolume{} + if attNameOk, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.name", i)); ok { + attName := attNameOk.(string) + if attName != "" { + volumeattItemModel.Name = &attName + } + } + if vname, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_name", i)); ok { + volName := vname.(string) + if volName != "" { + volumeattItemPrototypeModel.Name = &volName + } + } + if volAutoDelete, ok := d.GetOkExists(fmt.Sprintf("volume_prototypes.%d.delete_volume_on_instance_delete", i)); ok { + volumeattItemModel.DeleteVolumeOnInstanceDelete = core.BoolPtr(volAutoDelete.(bool)) + } + if volIops, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_iops", i)); ok { + if volIops.(int) != 0 { + volumeattItemPrototypeModel.Iops = core.Int64Ptr(int64(volIops.(int))) + } + } + if volCapacity, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_capacity", i)); ok { + if volCapacity != 0 { + volumeattItemPrototypeModel.Capacity = core.Int64Ptr(int64(volCapacity.(int))) + } + } + if volEncKeyOk, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_encryption_key", i)); ok { + volEncKey := volEncKeyOk.(string) + if volEncKey != "" { + volumeattItemPrototypeModel.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ + CRN: &volEncKey, + } + } + } + if volProfileOk, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_profile", i)); ok { + volProfile := volProfileOk.(string) + if volProfile != "" { + volumeattItemPrototypeModel.Profile = &vpcv1.VolumeProfileIdentity{ + Name: &volProfile, + } + } + } + if volRgOk, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_resource_group", i)); ok { + volRg := volRgOk.(string) + if volRg != "" { + volumeattItemPrototypeModel.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &volRg, + } + } + } + if volSnapshotok, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_source_snapshot", i)); ok { + volSnapshot := volSnapshotok.(string) + if volSnapshot != "" { + volumeattItemPrototypeModel.SourceSnapshot = &vpcv1.SnapshotIdentity{ + ID: &volSnapshot, + } + } + } + volTags := d.Get(fmt.Sprintf("volume_prototypes.%d.volume_tags", i)).(*schema.Set) + if volTags != nil && volTags.Len() != 0 { + userTagsArray := make([]string, volTags.Len()) + for i, userTag := range volTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + volumeattItemPrototypeModel.UserTags = userTagsArray + } + + volumeattItemModel.Volume = volumeattItemPrototypeModel + + volumeatt = append(volumeatt, *volumeattItemModel) + } + instanceproto.VolumeAttachments = volumeatt + } if _, ok := d.GetOk("confidential_compute_mode"); ok { instanceproto.ConfidentialComputeMode = core.StringPtr(d.Get("confidential_compute_mode").(string)) } @@ -2388,7 +2870,7 @@ func instanceCreateByCatalogOffering(d *schema.ResourceData, meta interface{}, p resAffinity.Policy = &policyStr } poolIntf, okPool := resAff[isReservationAffinityPool] - if okPool { + if okPool && poolIntf != nil && poolIntf.([]interface{}) != nil && len(poolIntf.([]interface{})) > 0 { pool := poolIntf.([]interface{})[0].(map[string]interface{}) id, okId := pool["id"] if okId { @@ -2665,6 +3147,100 @@ func instanceCreateByTemplate(d *schema.ResourceData, meta interface{}, profile, }, Name: &name, } + // cluster changes + if clusterNetworkAttachmentOk, ok := d.GetOk("cluster_network_attachments"); ok { + clusterNetworkAttachmentList := clusterNetworkAttachmentOk.([]interface{}) + if len(clusterNetworkAttachmentList) > 0 { + clusterNetworkAttachments := []vpcv1.InstanceClusterNetworkAttachmentPrototypeInstanceContext{} + for _, clusterNetworkAttachmentsItem := range clusterNetworkAttachmentList { + clusterNetworkAttachmentsItemModel, err := ResourceIBMIsInstanceMapToInstanceClusterNetworkAttachmentPrototypeInstanceContext(clusterNetworkAttachmentsItem.(map[string]interface{})) + if err != nil { + return err + } + clusterNetworkAttachments = append(clusterNetworkAttachments, *clusterNetworkAttachmentsItemModel) + } + instanceproto.ClusterNetworkAttachments = clusterNetworkAttachments + } + } + // volume_prototypes + if volumeattintf, ok := d.GetOk("volume_prototypes"); ok { + volumeatt := []vpcv1.VolumeAttachmentPrototype{} + for i, _ := range volumeattintf.([]interface{}) { + volumeattItemModel := &vpcv1.VolumeAttachmentPrototype{} + volumeattItemPrototypeModel := &vpcv1.VolumeAttachmentPrototypeVolume{} + if attNameOk, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.name", i)); ok { + attName := attNameOk.(string) + if attName != "" { + volumeattItemModel.Name = &attName + } + } + if vname, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_name", i)); ok { + volName := vname.(string) + if volName != "" { + volumeattItemPrototypeModel.Name = &volName + } + } + if volAutoDelete, ok := d.GetOkExists(fmt.Sprintf("volume_prototypes.%d.delete_volume_on_instance_delete", i)); ok { + volumeattItemModel.DeleteVolumeOnInstanceDelete = core.BoolPtr(volAutoDelete.(bool)) + } + if volIops, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_iops", i)); ok { + if volIops.(int) != 0 { + volumeattItemPrototypeModel.Iops = core.Int64Ptr(int64(volIops.(int))) + } + } + if volCapacity, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_capacity", i)); ok { + if volCapacity != 0 { + volumeattItemPrototypeModel.Capacity = core.Int64Ptr(int64(volCapacity.(int))) + } + } + if volEncKeyOk, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_encryption_key", i)); ok { + volEncKey := volEncKeyOk.(string) + if volEncKey != "" { + volumeattItemPrototypeModel.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ + CRN: &volEncKey, + } + } + } + if volProfileOk, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_profile", i)); ok { + volProfile := volProfileOk.(string) + if volProfile != "" { + volumeattItemPrototypeModel.Profile = &vpcv1.VolumeProfileIdentity{ + Name: &volProfile, + } + } + } + if volRgOk, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_resource_group", i)); ok { + volRg := volRgOk.(string) + if volRg != "" { + volumeattItemPrototypeModel.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &volRg, + } + } + } + if volSnapshotok, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_source_snapshot", i)); ok { + volSnapshot := volSnapshotok.(string) + if volSnapshot != "" { + volumeattItemPrototypeModel.SourceSnapshot = &vpcv1.SnapshotIdentity{ + ID: &volSnapshot, + } + } + } + volTags := d.Get(fmt.Sprintf("volume_prototypes.%d.volume_tags", i)).(*schema.Set) + if volTags != nil && volTags.Len() != 0 { + userTagsArray := make([]string, volTags.Len()) + for i, userTag := range volTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + volumeattItemPrototypeModel.UserTags = userTagsArray + } + + volumeattItemModel.Volume = volumeattItemPrototypeModel + + volumeatt = append(volumeatt, *volumeattItemModel) + } + instanceproto.VolumeAttachments = volumeatt + } if _, ok := d.GetOk("confidential_compute_mode"); ok { instanceproto.ConfidentialComputeMode = core.StringPtr(d.Get("confidential_compute_mode").(string)) } @@ -2823,7 +3399,7 @@ func instanceCreateByTemplate(d *schema.ResourceData, meta interface{}, profile, resAffinity.Policy = &policyStr } poolIntf, okPool := resAff[isReservationAffinityPool] - if okPool { + if okPool && poolIntf != nil && poolIntf.([]interface{}) != nil && len(poolIntf.([]interface{})) > 0 { pool := poolIntf.([]interface{})[0].(map[string]interface{}) id, okId := pool["id"] if okId { @@ -3113,6 +3689,100 @@ func instanceCreateBySnapshot(d *schema.ResourceData, meta interface{}, profile, ID: &vpcID, }, } + // cluster changes + if clusterNetworkAttachmentOk, ok := d.GetOk("cluster_network_attachments"); ok { + clusterNetworkAttachmentList := clusterNetworkAttachmentOk.([]interface{}) + if len(clusterNetworkAttachmentList) > 0 { + clusterNetworkAttachments := []vpcv1.InstanceClusterNetworkAttachmentPrototypeInstanceContext{} + for _, clusterNetworkAttachmentsItem := range clusterNetworkAttachmentList { + clusterNetworkAttachmentsItemModel, err := ResourceIBMIsInstanceMapToInstanceClusterNetworkAttachmentPrototypeInstanceContext(clusterNetworkAttachmentsItem.(map[string]interface{})) + if err != nil { + return err + } + clusterNetworkAttachments = append(clusterNetworkAttachments, *clusterNetworkAttachmentsItemModel) + } + instanceproto.ClusterNetworkAttachments = clusterNetworkAttachments + } + } + // volume_prototypes + if volumeattintf, ok := d.GetOk("volume_prototypes"); ok { + volumeatt := []vpcv1.VolumeAttachmentPrototype{} + for i, _ := range volumeattintf.([]interface{}) { + volumeattItemModel := &vpcv1.VolumeAttachmentPrototype{} + volumeattItemPrototypeModel := &vpcv1.VolumeAttachmentPrototypeVolume{} + if attNameOk, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.name", i)); ok { + attName := attNameOk.(string) + if attName != "" { + volumeattItemModel.Name = &attName + } + } + if vname, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_name", i)); ok { + volName := vname.(string) + if volName != "" { + volumeattItemPrototypeModel.Name = &volName + } + } + if volAutoDelete, ok := d.GetOkExists(fmt.Sprintf("volume_prototypes.%d.delete_volume_on_instance_delete", i)); ok { + volumeattItemModel.DeleteVolumeOnInstanceDelete = core.BoolPtr(volAutoDelete.(bool)) + } + if volIops, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_iops", i)); ok { + if volIops.(int) != 0 { + volumeattItemPrototypeModel.Iops = core.Int64Ptr(int64(volIops.(int))) + } + } + if volCapacity, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_capacity", i)); ok { + if volCapacity != 0 { + volumeattItemPrototypeModel.Capacity = core.Int64Ptr(int64(volCapacity.(int))) + } + } + if volEncKeyOk, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_encryption_key", i)); ok { + volEncKey := volEncKeyOk.(string) + if volEncKey != "" { + volumeattItemPrototypeModel.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ + CRN: &volEncKey, + } + } + } + if volProfileOk, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_profile", i)); ok { + volProfile := volProfileOk.(string) + if volProfile != "" { + volumeattItemPrototypeModel.Profile = &vpcv1.VolumeProfileIdentity{ + Name: &volProfile, + } + } + } + if volRgOk, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_resource_group", i)); ok { + volRg := volRgOk.(string) + if volRg != "" { + volumeattItemPrototypeModel.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &volRg, + } + } + } + if volSnapshotok, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_source_snapshot", i)); ok { + volSnapshot := volSnapshotok.(string) + if volSnapshot != "" { + volumeattItemPrototypeModel.SourceSnapshot = &vpcv1.SnapshotIdentity{ + ID: &volSnapshot, + } + } + } + volTags := d.Get(fmt.Sprintf("volume_prototypes.%d.volume_tags", i)).(*schema.Set) + if volTags != nil && volTags.Len() != 0 { + userTagsArray := make([]string, volTags.Len()) + for i, userTag := range volTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + volumeattItemPrototypeModel.UserTags = userTagsArray + } + + volumeattItemModel.Volume = volumeattItemPrototypeModel + + volumeatt = append(volumeatt, *volumeattItemModel) + } + instanceproto.VolumeAttachments = volumeatt + } if _, ok := d.GetOk("confidential_compute_mode"); ok { instanceproto.ConfidentialComputeMode = core.StringPtr(d.Get("confidential_compute_mode").(string)) } @@ -3233,7 +3903,7 @@ func instanceCreateBySnapshot(d *schema.ResourceData, meta interface{}, profile, resAffinity.Policy = &policyStr } poolIntf, okPool := resAff[isReservationAffinityPool] - if okPool { + if okPool && poolIntf != nil && poolIntf.([]interface{}) != nil && len(poolIntf.([]interface{})) > 0 { pool := poolIntf.([]interface{})[0].(map[string]interface{}) id, okId := pool["id"] if okId { @@ -3559,6 +4229,100 @@ func instanceCreateByVolume(d *schema.ResourceData, meta interface{}, profile, n ID: &vpcID, }, } + // cluster changes + if clusterNetworkAttachmentOk, ok := d.GetOk("cluster_network_attachments"); ok { + clusterNetworkAttachmentList := clusterNetworkAttachmentOk.([]interface{}) + if len(clusterNetworkAttachmentList) > 0 { + clusterNetworkAttachments := []vpcv1.InstanceClusterNetworkAttachmentPrototypeInstanceContext{} + for _, clusterNetworkAttachmentsItem := range clusterNetworkAttachmentList { + clusterNetworkAttachmentsItemModel, err := ResourceIBMIsInstanceMapToInstanceClusterNetworkAttachmentPrototypeInstanceContext(clusterNetworkAttachmentsItem.(map[string]interface{})) + if err != nil { + return err + } + clusterNetworkAttachments = append(clusterNetworkAttachments, *clusterNetworkAttachmentsItemModel) + } + instanceproto.ClusterNetworkAttachments = clusterNetworkAttachments + } + } + // volume_prototypes + if volumeattintf, ok := d.GetOk("volume_prototypes"); ok { + volumeatt := []vpcv1.VolumeAttachmentPrototype{} + for i, _ := range volumeattintf.([]interface{}) { + volumeattItemModel := &vpcv1.VolumeAttachmentPrototype{} + volumeattItemPrototypeModel := &vpcv1.VolumeAttachmentPrototypeVolume{} + if attNameOk, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.name", i)); ok { + attName := attNameOk.(string) + if attName != "" { + volumeattItemModel.Name = &attName + } + } + if vname, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_name", i)); ok { + volName := vname.(string) + if volName != "" { + volumeattItemPrototypeModel.Name = &volName + } + } + if volAutoDelete, ok := d.GetOkExists(fmt.Sprintf("volume_prototypes.%d.delete_volume_on_instance_delete", i)); ok { + volumeattItemModel.DeleteVolumeOnInstanceDelete = core.BoolPtr(volAutoDelete.(bool)) + } + if volIops, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_iops", i)); ok { + if volIops.(int) != 0 { + volumeattItemPrototypeModel.Iops = core.Int64Ptr(int64(volIops.(int))) + } + } + if volCapacity, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_capacity", i)); ok { + if volCapacity != 0 { + volumeattItemPrototypeModel.Capacity = core.Int64Ptr(int64(volCapacity.(int))) + } + } + if volEncKeyOk, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_encryption_key", i)); ok { + volEncKey := volEncKeyOk.(string) + if volEncKey != "" { + volumeattItemPrototypeModel.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ + CRN: &volEncKey, + } + } + } + if volProfileOk, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_profile", i)); ok { + volProfile := volProfileOk.(string) + if volProfile != "" { + volumeattItemPrototypeModel.Profile = &vpcv1.VolumeProfileIdentity{ + Name: &volProfile, + } + } + } + if volRgOk, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_resource_group", i)); ok { + volRg := volRgOk.(string) + if volRg != "" { + volumeattItemPrototypeModel.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &volRg, + } + } + } + if volSnapshotok, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.volume_source_snapshot", i)); ok { + volSnapshot := volSnapshotok.(string) + if volSnapshot != "" { + volumeattItemPrototypeModel.SourceSnapshot = &vpcv1.SnapshotIdentity{ + ID: &volSnapshot, + } + } + } + volTags := d.Get(fmt.Sprintf("volume_prototypes.%d.volume_tags", i)).(*schema.Set) + if volTags != nil && volTags.Len() != 0 { + userTagsArray := make([]string, volTags.Len()) + for i, userTag := range volTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + volumeattItemPrototypeModel.UserTags = userTagsArray + } + + volumeattItemModel.Volume = volumeattItemPrototypeModel + + volumeatt = append(volumeatt, *volumeattItemModel) + } + instanceproto.VolumeAttachments = volumeatt + } if _, ok := d.GetOk("confidential_compute_mode"); ok { instanceproto.ConfidentialComputeMode = core.StringPtr(d.Get("confidential_compute_mode").(string)) } @@ -3632,7 +4396,7 @@ func instanceCreateByVolume(d *schema.ResourceData, meta interface{}, profile, n resAffinity.Policy = &policyStr } poolIntf, okPool := resAff[isReservationAffinityPool] - if okPool { + if okPool && poolIntf != nil && poolIntf.([]interface{}) != nil && len(poolIntf.([]interface{})) > 0 { pool := poolIntf.([]interface{})[0].(map[string]interface{}) id, okId := pool["id"] if okId { @@ -4134,6 +4898,31 @@ func instanceGet(d *schema.ResourceData, meta interface{}, id string) error { } return fmt.Errorf("[ERROR] Error getting Instance: %s\n%s", err, response) } + // cluster changes + if !core.IsNil(instance.ClusterNetworkAttachments) { + clusterNetworkAttachments := []map[string]interface{}{} + for _, clusterNetworkAttachmentsItem := range instance.ClusterNetworkAttachments { + clusterNetworkAttachmentsItemMap, err := ResourceIBMIsInstanceInstanceClusterNetworkAttachmentReferenceToMap(instanceC, &clusterNetworkAttachmentsItem, *instance.ID) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance", "read", "cluster_network_attachments-to-map") + } + clusterNetworkAttachments = append(clusterNetworkAttachments, clusterNetworkAttachmentsItemMap) + } + if err = d.Set("cluster_network_attachments", clusterNetworkAttachments); err != nil { + err = fmt.Errorf("Error setting cluster_network_attachments: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance", "read", "set-cluster_network_attachments") + } + } + if !core.IsNil(instance.ClusterNetwork) { + clusterNetworkMap, err := ResourceIBMIsInstanceClusterNetworkReferenceToMap(instance.ClusterNetwork) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance", "read", "cluster_network-to-map") + } + if err = d.Set("cluster_network", []map[string]interface{}{clusterNetworkMap}); err != nil { + err = fmt.Errorf("Error setting cluster_network: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance", "read", "set-cluster_network") + } + } if !core.IsNil(instance.ConfidentialComputeMode) { if err = d.Set("confidential_compute_mode", instance.ConfidentialComputeMode); err != nil { return fmt.Errorf("Error setting confidential_compute_mode: %s", err) @@ -4159,6 +4948,10 @@ func instanceGet(d *schema.ResourceData, meta interface{}, id string) error { d.Set(isInstanceAvailablePolicyHostFailure, *instance.AvailabilityPolicy.HostFailure) } + // volume_prototypes + volList, _ := setVolumePrototypesInState(d, instance, instanceC) + d.Set("volume_prototypes", volList) + // catalog if instance.CatalogOffering != nil { versionCrn := *instance.CatalogOffering.Version.CRN @@ -4277,6 +5070,24 @@ func instanceGet(d *schema.ResourceData, meta interface{}, id string) error { primaryNicList = append(primaryNicList, currentPrimNic) d.Set(isInstancePrimaryNetworkInterface, primaryNicList) } + if instance.HealthReasons != nil { + healthReasonsList := make([]map[string]interface{}, 0) + for _, sr := range instance.HealthReasons { + currentSR := map[string]interface{}{} + if sr.Code != nil && sr.Message != nil { + currentSR["code"] = *sr.Code + currentSR["message"] = *sr.Message + if sr.MoreInfo != nil { + currentSR["more_info"] = *sr.Message + } + healthReasonsList = append(healthReasonsList, currentSR) + } + } + d.Set("health_reasons", healthReasonsList) + } + if err = d.Set("health_state", instance.HealthState); err != nil { + return err + } if instance.ReservationAffinity != nil { reservationAffinity := []map[string]interface{}{} reservationAffinityMap := map[string]interface{}{} @@ -4294,7 +5105,7 @@ func instanceGet(d *schema.ResourceData, meta interface{}, id string) error { res[isReservationResourceType] = *pool.ResourceType if pool.Deleted != nil { deletedList := []map[string]interface{}{} - deletedMap := dataSourceInstanceReservationDeletedToMap(*pool.Deleted) + deletedMap := dataSourceReservationDeletedToMap(*pool.Deleted) deletedList = append(deletedList, deletedMap) res[isReservationDeleted] = deletedList } @@ -4316,7 +5127,7 @@ func instanceGet(d *schema.ResourceData, meta interface{}, id string) error { res[isReservationResourceType] = *instance.Reservation.ResourceType if instance.Reservation.Deleted != nil { deletedList := []map[string]interface{}{} - deletedMap := dataSourceInstanceReservationDeletedToMap(*instance.Reservation.Deleted) + deletedMap := dataSourceReservationDeletedToMap(*instance.Reservation.Deleted) deletedList = append(deletedList, deletedMap) res[isReservationDeleted] = deletedList } @@ -4611,6 +5422,11 @@ func instanceUpdate(d *schema.ResourceData, meta interface{}) error { id := d.Id() // network attachments + err = handleVolumePrototypesUpdate(d, instanceC) + if err != nil { + return err + } + if d.HasChange("network_attachments") && !d.IsNewResource() { nacs := d.Get("network_attachments").([]interface{}) ots, nts := d.GetChange("network_attachments") @@ -5101,7 +5917,7 @@ func instanceUpdate(d *schema.ResourceData, meta interface{}) error { } if d.HasChange(resPool) { poolIntf, okPool := resAff[isReservationAffinityPool] - if okPool { + if okPool && poolIntf != nil && poolIntf.([]interface{}) != nil && len(poolIntf.([]interface{})) > 0 { pool := poolIntf.([]interface{})[0].(map[string]interface{}) id, okId := pool["id"] if okId { @@ -6056,7 +6872,7 @@ func instanceDelete(d *schema.ResourceData, meta interface{}, id string) error { return fmt.Errorf("[ERROR] Error Listing volume attachments to the instance: %s\n%s", err, response) } for _, vol := range vols.VolumeAttachments { - if *vol.Type == "data" { + if *vol.Type == "data" && *vol.DeleteVolumeOnInstanceDelete { delvolattoptions := &vpcv1.DeleteInstanceVolumeAttachmentOptions{ InstanceID: &id, ID: vol.ID, @@ -6375,15 +7191,6 @@ func resourceIbmIsInstanceInstancePlacementToMap(instancePlacement vpcv1.Instanc return instancePlacementMap } -func resourceIbmIsInstanceReservationAffinityPoolToMap(reservationPool vpcv1.ReservationReference) map[string]interface{} { - resAffPoolMap := map[string]interface{}{} - - resAffPoolMap["crn"] = reservationPool.CRN - resAffPoolMap["href"] = reservationPool.Href - resAffPoolMap["id"] = reservationPool.ID - return resAffPoolMap -} - func resourceIbmIsInstanceDedicatedHostGroupReferenceDeletedToMap(dedicatedHostGroupReferenceDeleted vpcv1.Deleted) map[string]interface{} { dedicatedHostGroupReferenceDeletedMap := map[string]interface{}{} @@ -6651,3 +7458,693 @@ func containsNacId(s []string, e string) bool { } return false } + +func ResourceIBMIsInstanceInstanceClusterNetworkAttachmentReferenceToMap(instanceC *vpcv1.VpcV1, model *vpcv1.InstanceClusterNetworkAttachmentReference, id string) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["id"] = *model.ID + modelMap["name"] = *model.Name + getInstanceClusterNetworkAttachment := &vpcv1.GetInstanceClusterNetworkAttachmentOptions{ + InstanceID: &id, + ID: model.ID, + } + clusterNetworkAttachment, _, err := instanceC.GetInstanceClusterNetworkAttachment(getInstanceClusterNetworkAttachment) + if err != nil { + return modelMap, err + } + if clusterNetworkAttachment.ClusterNetworkInterface != nil { + clusterMap, err := ResourceIBMIsInstanceClusterNetworkAttachmentToMap(clusterNetworkAttachment) + if err != nil { + return modelMap, err + } + modelMap["cluster_network_interface"] = []map[string]interface{}{clusterMap} + } + + return modelMap, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentToMap(cnamodel *vpcv1.InstanceClusterNetworkAttachment) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + model := cnamodel.ClusterNetworkInterface + if model.Deleted != nil { + deletedMap, err := ResourceIBMIsInstanceDeletedToMap(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.Subnet != nil { + subnetMap, err := ResourceIBMIsInstanceClusterNetworkInterfaceSubnetToMap(model.Subnet) + if err != nil { + return modelMap, err + } + modelMap["subnet"] = []map[string]interface{}{subnetMap} + } + if model.PrimaryIP != nil { + primaryipMap, err := ResourceIBMIsInstanceClusterNetworkInterfacePrimaryIPToMap(model.PrimaryIP) + if err != nil { + return modelMap, err + } + modelMap["primary_ip"] = []map[string]interface{}{primaryipMap} + } + return modelMap, nil +} +func ResourceIBMIsInstanceClusterNetworkInterfacePrimaryIPToMap(model *vpcv1.ClusterNetworkSubnetReservedIPReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["address"] = *model.Address + modelMap["href"] = *model.Href + modelMap["id"] = *model.ID + modelMap["name"] = *model.Name + return modelMap, nil +} +func ResourceIBMIsInstanceClusterNetworkInterfaceSubnetToMap(model *vpcv1.ClusterNetworkSubnetReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["id"] = *model.ID + return modelMap, nil +} +func ResourceIBMIsInstanceClusterNetworkReferenceToMap(model *vpcv1.ClusterNetworkReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["crn"] = *model.CRN + if model.Deleted != nil { + deletedMap, err := ResourceIBMIsInstanceDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func ResourceIBMIsInstanceDeletedToMap(model *vpcv1.Deleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = *model.MoreInfo + return modelMap, nil +} + +func ResourceIBMIsInstanceMapToInstanceClusterNetworkAttachmentPrototypeInstanceContext(modelMap map[string]interface{}) (*vpcv1.InstanceClusterNetworkAttachmentPrototypeInstanceContext, error) { + model := &vpcv1.InstanceClusterNetworkAttachmentPrototypeInstanceContext{} + ClusterNetworkInterfaceModel, err := ResourceIBMIsInstanceMapToInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterface(modelMap["cluster_network_interface"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.ClusterNetworkInterface = ClusterNetworkInterfaceModel + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + return model, nil +} + +func ResourceIBMIsInstanceMapToInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterface(modelMap map[string]interface{}) (vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceIntf, error) { + model := &vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterface{} + if modelMap["auto_delete"] != nil { + model.AutoDelete = core.BoolPtr(modelMap["auto_delete"].(bool)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["primary_ip"] != nil && len(modelMap["primary_ip"].([]interface{})) > 0 { + PrimaryIPModel, err := ResourceIBMIsInstanceMapToClusterNetworkInterfacePrimaryIPPrototype(modelMap["primary_ip"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.PrimaryIP = PrimaryIPModel + } + if modelMap["subnet"] != nil && len(modelMap["subnet"].([]interface{})) > 0 { + SubnetModel, err := ResourceIBMIsInstanceMapToClusterNetworkSubnetIdentity(modelMap["subnet"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Subnet = SubnetModel + } + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["href"] != nil && modelMap["href"].(string) != "" { + model.Href = core.StringPtr(modelMap["href"].(string)) + } + return model, nil +} + +func ResourceIBMIsInstanceMapToClusterNetworkInterfacePrimaryIPPrototype(modelMap map[string]interface{}) (vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeIntf, error) { + model := &vpcv1.ClusterNetworkInterfacePrimaryIPPrototype{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["href"] != nil && modelMap["href"].(string) != "" { + model.Href = core.StringPtr(modelMap["href"].(string)) + } + if modelMap["address"] != nil && modelMap["address"].(string) != "" { + model.Address = core.StringPtr(modelMap["address"].(string)) + } + if modelMap["auto_delete"] != nil { + model.AutoDelete = core.BoolPtr(modelMap["auto_delete"].(bool)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + return model, nil +} +func ResourceIBMIsInstanceMapToClusterNetworkSubnetIdentity(modelMap map[string]interface{}) (vpcv1.ClusterNetworkSubnetIdentityIntf, error) { + model := &vpcv1.ClusterNetworkSubnetIdentity{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["href"] != nil && modelMap["href"].(string) != "" { + model.Href = core.StringPtr(modelMap["href"].(string)) + } + return model, nil +} +func diffSuppressVolumePrototypes(k, old, new string, d *schema.ResourceData) bool { + if d.Id() == "" { + return false + } + + o, n := d.GetChange("volume_prototypes") + oldList := o.([]interface{}) + newList := n.([]interface{}) + + if len(oldList) != len(newList) { + return false + } + + // First, find which volume in new list corresponds to each old volume by name + volMap := make(map[string]int) // maps attachment name to position in new list + for i, v := range newList { + vol := v.(map[string]interface{}) + attachmentName := vol["name"].(string) + volMap[attachmentName] = i + } + + // Compare each old volume with its corresponding new volume + for _, oldVol := range oldList { + oldVolMap := oldVol.(map[string]interface{}) + attachmentName := oldVolMap["name"].(string) + + // Find corresponding new volume + newIndex, exists := volMap[attachmentName] + if !exists { + return false + } + + newVol := newList[newIndex].(map[string]interface{}) + + // Compare relevant fields + if !volumesEqual(oldVolMap, newVol) { + return false + } + } + + return true +} + +func volumesEqual(oldVol, newVol map[string]interface{}) bool { + fieldsToCompare := []string{ + "delete_volume_on_instance_delete", + "volume_name", + "volume_capacity", + "volume_profile", + "volume_source_snapshot", + "volume_encryption_key", + "volume_tags", + } + + for _, field := range fieldsToCompare { + oldVal, oldOk := oldVol[field] + newVal, newOk := newVol[field] + + if oldOk != newOk { + return false + } + + if oldOk && newOk { + if field == "volume_tags" { + if !compareVolumeTags(oldVal, newVal) { + return false + } + continue + } + + if !reflect.DeepEqual(oldVal, newVal) { + return false + } + } + } + + // Handle IOPS specially based on profile + profile := oldVol["volume_profile"].(string) + if !isTieredProfile(profile) { + oldIops, oldOk := oldVol["volume_iops"] + newIops, newOk := newVol["volume_iops"] + + if oldOk != newOk { + return false + } + + if oldOk && newOk && !reflect.DeepEqual(oldIops, newIops) { + return false + } + } + + return true +} + +// Validation function +func ResourceValidateInstanceVolumePrototypes(diff *schema.ResourceDiff, meta interface{}) error { + // For new resource creation + if diff.Id() == "" { + volProtoListIntf := diff.Get("volume_prototypes") + if volProtoListIntf == nil { + return nil + } + + volProtoList := volProtoListIntf.([]interface{}) + for i, vol := range volProtoList { + volMap := vol.(map[string]interface{}) + profile := volMap["volume_profile"].(string) + + // For tiered profiles, validate IOPS not set + if isTieredProfile(profile) { + if iops, ok := volMap["volume_iops"]; ok && iops.(int) != 0 { + return fmt.Errorf("volume prototype %d (%s): iops cannot be set for tiered profile %s", + i, volMap["volume_name"].(string), profile) + } + } + } + return nil + } + + // For updates + if !diff.HasChange("volume_prototypes") { + return nil + } + + oldVolProtoListIntf, newVolProtoListIntf := diff.GetChange("volume_prototypes") + if oldVolProtoListIntf == nil || newVolProtoListIntf == nil { + return nil + } + + oldVolProtoList := oldVolProtoListIntf.([]interface{}) + newVolProtoList := newVolProtoListIntf.([]interface{}) + + oldVolMap := make(map[string]map[string]interface{}) + for _, v := range oldVolProtoList { + volMap := v.(map[string]interface{}) + oldVolMap[volMap["volume_name"].(string)] = volMap + } + + // Validate each volume + for _, v := range newVolProtoList { + volMap := v.(map[string]interface{}) + volName := volMap["volume_name"].(string) + newProfile := volMap["volume_profile"].(string) + + if oldVol, exists := oldVolMap[volName]; exists { + oldProfile := oldVol["volume_profile"].(string) + + // Validate profile transitions + if oldProfile != newProfile { + if oldProfile == "custom" && newProfile != "custom" { + return fmt.Errorf("volume %s: custom profile can only be changed to another custom profile", volName) + } + if isTieredProfile(oldProfile) && !isTieredProfile(newProfile) { + return fmt.Errorf("volume %s: tiered profile can only be changed to another tiered profile", volName) + } + } + } + + // Validate tiered profile constraints + if isTieredProfile(newProfile) { + if iops, ok := volMap["volume_iops"]; ok && iops.(int) != 0 { + return fmt.Errorf("volume %s: iops cannot be set for tiered profile", volName) + } + } + } + + return nil +} + +func handleVolumePrototypesUpdate(d *schema.ResourceData, instanceC *vpcv1.VpcV1) error { + if !d.HasChange("volume_prototypes") || d.IsNewResource() { + return nil + } + + instanceID := d.Id() + o, n := d.GetChange("volume_prototypes") + oldList := o.([]interface{}) + newList := n.([]interface{}) + + // Track processed old volumes + processedOldVolumes := make(map[string]bool) + + // First create a map of old volumes by name for easy lookup + oldVolMap := make(map[string]map[string]interface{}) + for _, v := range oldList { + vol := v.(map[string]interface{}) + name := vol["name"].(string) + oldVolMap[name] = vol + } + + // Process new list for updates and additions + for i, newVolInterface := range newList { + newVol := newVolInterface.(map[string]interface{}) + name := newVol["name"].(string) + + // Check if volume exists in old list + if oldVol, exists := oldVolMap[name]; exists { + // Mark as processed + processedOldVolumes[name] = true + + // Check if update is needed + if hasVolumeChanged(d, i, oldVol, newVol) { + // Handle update + volID := oldVol["volume_id"].(string) + + voloptions := &vpcv1.UpdateVolumeOptions{ + ID: &volID, + } + getvoloptions := &vpcv1.GetVolumeOptions{ + ID: &volID, + } + _, res, err := instanceC.GetVolume(getvoloptions) + if err != nil { + return fmt.Errorf("error getting volume for patch for %s: %w", name, err) + } + eTag := res.Headers.Get("ETag") + volumePatchModel := &vpcv1.VolumePatch{} + if newVol["volume_profile"].(string) != oldVol["volume_profile"].(string) && isTieredProfile(newVol["volume_profile"].(string)) { + volumePatchModel.Profile = &vpcv1.VolumeProfileIdentity{ + Name: core.StringPtr(newVol["volume_profile"].(string)), + } + } + if newVol["volume_name"].(string) != oldVol["volume_name"].(string) { + volumePatchModel.Name = core.StringPtr(newVol["volume_name"].(string)) + } + if newVol["volume_tags"] == nil && oldVol["volume_tags"] == nil { + // do nothing + } else if newVol["volume_tags"] == nil && oldVol["volume_tags"] != nil { + volumePatchModel.UserTags = nil + } else if (newVol["volume_tags"] != nil && oldVol["volume_tags"] == nil) || (!newVol["volume_tags"].(*schema.Set).Equal(oldVol["volume_tags"].(*schema.Set))) { + userTags := newVol["volume_tags"].(*schema.Set) + userTagsArray := make([]string, userTags.Len()) + for i, userTag := range userTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + volumePatchModel.UserTags = userTagsArray + } + volumePatch, err := volumePatchModel.AsPatch() + if err != nil { + return fmt.Errorf("error creating volume patch for %s: %w", name, err) + } + voloptions.VolumePatch = volumePatch + voloptions.SetIfMatch(eTag) + _, response, err := instanceC.UpdateVolume(voloptions) + if err != nil { + return fmt.Errorf("error updating volume %s: %s\n%s", name, err, response) + } + eTag = response.Headers.Get("ETag") + + // Only include IOPS for non-tiered profiles + if !isTieredProfile(newVol["volume_profile"].(string)) && (int64(newVol["volume_iops"].(int)) != int64(oldVol["volume_iops"].(int))) { + volumeIopsPatchModel := &vpcv1.VolumePatch{} + iops := int64(newVol["volume_iops"].(int)) + volumeIopsPatchModel.Iops = &iops + volumePatch, err := volumeIopsPatchModel.AsPatch() + if err != nil { + return fmt.Errorf("error creating volume patch for iops update %s: %w", name, err) + } + voloptions.VolumePatch = volumePatch + voloptions.SetIfMatch(eTag) + _, response, err := instanceC.UpdateVolume(voloptions) + if err != nil { + return fmt.Errorf("error updating volume during iops update %s: %s\n%s", name, err, response) + } + eTag = response.Headers.Get("ETag") + } + // Only include capacity update + if int64(newVol["volume_capacity"].(int)) != int64(oldVol["volume_capacity"].(int)) { + volumeCapacityPatchModel := &vpcv1.VolumePatch{} + capacity := int64(newVol["volume_capacity"].(int)) + volumeCapacityPatchModel.Capacity = &capacity + volumePatch, err := volumeCapacityPatchModel.AsPatch() + if err != nil { + return fmt.Errorf("error creating volume patch for capacity update %s: %w", name, err) + } + voloptions.SetIfMatch(eTag) + voloptions.VolumePatch = volumePatch + _, response, err := instanceC.UpdateVolume(voloptions) + if err != nil { + return fmt.Errorf("error updating volume during capacity update %s: %s\n%s", name, err, response) + } + eTag = response.Headers.Get("ETag") + } + } + } else { + // Handle addition + profile := newVol["volume_profile"].(string) + capacity := int64(newVol["volume_capacity"].(int)) + volumeName := newVol["volume_name"].(string) + + createvolattoptions := &vpcv1.CreateInstanceVolumeAttachmentOptions{ + InstanceID: &instanceID, + } + volAtt := &vpcv1.VolumeAttachmentPrototypeVolume{ + Name: &volumeName, + Profile: &vpcv1.VolumeProfileIdentity{ + Name: &profile, + }, + Capacity: &capacity, + } + // Handle delete_volume_on_instance_delete using GetOkExists only for new volumes + if volAutoDelete, ok := d.GetOkExists(fmt.Sprintf("volume_prototypes.%d.delete_volume_on_instance_delete", i)); ok { + createvolattoptions.DeleteVolumeOnInstanceDelete = core.BoolPtr(volAutoDelete.(bool)) + } + + // Only set IOPS for non-tiered profiles + if !isTieredProfile(profile) { + iops := int64(newVol["volume_iops"].(int)) + volAtt.Iops = &iops + } + createvolattoptions.Volume = volAtt + newVolume, _, err := instanceC.CreateInstanceVolumeAttachment(createvolattoptions) + if err != nil { + return fmt.Errorf("error attaching volume %s: %w", name, err) + } + + _, err = isWaitForInstanceVolumeAttached(instanceC, d, instanceID, *newVolume.ID) + if err != nil { + return err + } + } + } + + // Handle deletions - anything in old list that wasn't processed + for _, oldVolInterface := range oldList { + oldVol := oldVolInterface.(map[string]interface{}) + name := oldVol["name"].(string) + + if !processedOldVolumes[name] { + // Handle deletion + volID := oldVol["id"].(string) + + delvolattoptions := &vpcv1.DeleteInstanceVolumeAttachmentOptions{ + InstanceID: &instanceID, + ID: &volID, + } + + _, err := instanceC.DeleteInstanceVolumeAttachment(delvolattoptions) + if err != nil { + return fmt.Errorf("error removing volume %s: %w", name, err) + } + + _, err = isWaitForInstanceVolumeDetached(instanceC, d, instanceID, volID) + if err != nil { + return err + } + } + } + + return nil +} + +// Modified to handle boolean comparison correctly between state and config +func hasVolumeChanged(d *schema.ResourceData, newIndex int, oldVol, newVol map[string]interface{}) bool { + fieldsToCompare := []string{ + "volume_name", + "volume_capacity", + "volume_profile", + } + + // Compare standard fields + for _, field := range fieldsToCompare { + oldVal := oldVol[field] + newVal := newVol[field] + + if !reflect.DeepEqual(oldVal, newVal) { + return true + } + } + + // Compare delete_volume_on_instance_delete + // For old (state), direct access + oldAutoDelete := oldVol["delete_volume_on_instance_delete"].(bool) + + // For new (config), use GetOkExists + if newAutoDelete, ok := d.GetOkExists(fmt.Sprintf("volume_prototypes.%d.delete_volume_on_instance_delete", newIndex)); ok { + if oldAutoDelete != newAutoDelete.(bool) { + return true + } + } + + // Special handling for IOPS based on profile + newProfile := newVol["volume_profile"].(string) + + if !isTieredProfile(newProfile) { + oldIops := oldVol["volume_iops"].(int) + newIops := newVol["volume_iops"].(int) + if oldIops != newIops { + return true + } + } + + return false +} + +func isTieredProfile(profile string) bool { + switch profile { + case "general-purpose", "10iops-tier", "5iops-tier": + return true + default: + return false + } +} + +// Helper function to compare volume tags +func compareVolumeTags(old, new interface{}) bool { + if old == nil && new == nil { + return true + } + if old == nil || new == nil { + return false + } + + oldSet := old.(*schema.Set) + newSet := new.(*schema.Set) + + return oldSet.Len() == newSet.Len() && oldSet.Difference(newSet).Len() == 0 +} + +func prettifyResponse(response interface{}) string { + output, err := json.MarshalIndent(response, "", " ") + if err == nil { + return fmt.Sprintf("%+v\n", string(output)) + } + return fmt.Sprintf("Error : %#v", response) +} + +func setVolumePrototypesInState(d *schema.ResourceData, instance *vpcv1.Instance, instanceC *vpcv1.VpcV1) ([]map[string]interface{}, error) { + if instance.VolumeAttachments == nil { + return nil, nil + } + + // First get the config order + configVolumes := make(map[string]int) // maps attachment name to position + if configList, ok := d.GetOk("volume_prototypes"); ok { + for i, v := range configList.([]interface{}) { + vol := v.(map[string]interface{}) + if name, ok := vol["name"].(string); ok { + configVolumes[name] = i + } + } + } + + // Create a map for current volumes + currentVolumes := make(map[string]map[string]interface{}) + maxPosition := -1 + + // Process all volumes + for _, volume := range instance.VolumeAttachments { + if *volume.ID != *instance.BootVolumeAttachment.ID { + vol := map[string]interface{}{} + + if volume.Volume != nil { + getVolOptions := &vpcv1.GetVolumeOptions{ + ID: volume.Volume.ID, + } + + getInstanceVolumeAttachmentOptions := &vpcv1.GetInstanceVolumeAttachmentOptions{ + InstanceID: core.StringPtr(d.Id()), + ID: volume.ID, + } + + volumeRef, _, err := instanceC.GetVolume(getVolOptions) + if err != nil { + vol["id"] = *volume.ID + vol["volume_id"] = *volume.Volume.ID + vol["name"] = *volume.Name + vol["volume_name"] = *volume.Volume.Name + vol["volume_crn"] = *volume.Volume.CRN + vol["volume_resource_type"] = *volume.Volume.ResourceType + } else { + vol["id"] = *volume.ID + vol["volume_id"] = *volume.Volume.ID + vol["name"] = *volume.Name + vol["volume_name"] = *volumeRef.Name + vol["volume_profile"] = *volumeRef.Profile.Name + vol["volume_iops"] = *volumeRef.Iops + vol["volume_capacity"] = *volumeRef.Capacity + vol["volume_crn"] = *volume.Volume.CRN + vol["volume_resource_type"] = *volume.Volume.ResourceType + } + + volumeAttRef, _, err := instanceC.GetInstanceVolumeAttachment(getInstanceVolumeAttachmentOptions) + if err != nil { + vol["delete_volume_on_instance_delete"] = true + } else { + vol["delete_volume_on_instance_delete"] = volumeAttRef.DeleteVolumeOnInstanceDelete + } + + currentVolumes[*volume.Name] = vol + + // Track maximum position + if pos, exists := configVolumes[*volume.Name]; exists { + if pos > maxPosition { + maxPosition = pos + } + } + } + } + } + + // Create ordered list based on config positions + orderedList := make([]map[string]interface{}, maxPosition+1) + unorderedVolumes := make([]map[string]interface{}, 0) + + // First place volumes that exist in config + for name, vol := range currentVolumes { + if pos, exists := configVolumes[name]; exists { + orderedList[pos] = vol + } else { + unorderedVolumes = append(unorderedVolumes, vol) + } + } + + // Remove nil entries and append any volumes not in config + finalList := make([]map[string]interface{}, 0) + for _, vol := range orderedList { + if vol != nil { + finalList = append(finalList, vol) + } + } + finalList = append(finalList, unorderedVolumes...) + + return finalList, nil +} diff --git a/ibm/service/vpc/resource_ibm_is_instance_cluster_network_attachment.go b/ibm/service/vpc/resource_ibm_is_instance_cluster_network_attachment.go new file mode 100644 index 0000000000..9920f41371 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_instance_cluster_network_attachment.go @@ -0,0 +1,766 @@ +// Copyright IBM Corp. 2024 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/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func ResourceIBMIsInstanceClusterNetworkAttachment() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIBMIsInstanceClusterNetworkAttachmentCreate, + ReadContext: resourceIBMIsInstanceClusterNetworkAttachmentRead, + UpdateContext: resourceIBMIsInstanceClusterNetworkAttachmentUpdate, + DeleteContext: resourceIBMIsInstanceClusterNetworkAttachmentDelete, + Importer: &schema.ResourceImporter{}, + + Schema: map[string]*schema.Schema{ + "instance_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_cluster_network_attachment", "instance_id"), + Description: "The virtual server instance identifier.", + }, + "before": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: "The instance cluster network attachment that is immediately before. If absent, this is thelast instance cluster network attachment.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this instance cluster network attachment.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The unique identifier for this instance cluster network attachment.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this instance cluster network attachment. The name is unique across all network attachments for the instance.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "cluster_network_interface": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Required: true, + Description: "The cluster network interface for this instance cluster network attachment.", + 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 cluster network interface.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this cluster network interface.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The name for this cluster network interface. The name is unique across all interfaces in the cluster network.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "The primary IP for this cluster network interface.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The IP address.If the address is pending allocation, the value will be `0.0.0.0`.This property may [expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) to support IPv6 addresses in the future.", + }, + "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, + Required: true, + Description: "The URL for this cluster network subnet reserved IP.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The unique identifier for this cluster network subnet reserved IP.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The name for this cluster network subnet reserved IP. The name is unique across all reserved IPs in a cluster network subnet.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "subnet": &schema.Schema{ + Type: schema.TypeList, + MinItems: 1, + MaxItems: 1, + Required: true, + 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 cluster network subnet.", + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The unique identifier for this cluster network subnet.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this cluster network subnet. The name is unique across all cluster network subnets in the cluster network.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_cluster_network_attachment", "name"), + Description: "The name for this instance cluster network attachment. The name is unique across all network attachments for the instance.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this instance cluster network attachment.", + }, + "lifecycle_reasons": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current `lifecycle_state` (if any).", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "message": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the reason for this lifecycle state.", + }, + "more_info": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Link to documentation about the reason for this lifecycle state.", + }, + }, + }, + }, + "lifecycle_state": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the instance cluster network attachment.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "instance_cluster_network_attachment_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this instance cluster network attachment.", + }, + }, + } +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "instance_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[-0-9a-z_]+$`, + MinValueLength: 1, + MaxValueLength: 64, + }, + 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, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_instance_cluster_network_attachment", Schema: validateSchema} + return &resourceValidator +} + +func resourceIBMIsInstanceClusterNetworkAttachmentCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_cluster_network_attachment", "create", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + createClusterNetworkAttachmentOptions := &vpcv1.CreateClusterNetworkAttachmentOptions{} + + createClusterNetworkAttachmentOptions.SetInstanceID(d.Get("instance_id").(string)) + clusterNetworkInterfaceModel, err := ResourceIBMIsInstanceClusterNetworkAttachmentMapToInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterface(d.Get("cluster_network_interface.0").(map[string]interface{})) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_cluster_network_attachment", "create", "parse-cluster_network_interface").GetDiag() + } + createClusterNetworkAttachmentOptions.SetClusterNetworkInterface(clusterNetworkInterfaceModel) + if _, ok := d.GetOk("before"); ok { + beforeModel, err := ResourceIBMIsInstanceClusterNetworkAttachmentMapToInstanceClusterNetworkAttachmentBeforePrototype(d.Get("before.0").(map[string]interface{})) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_cluster_network_attachment", "create", "parse-before").GetDiag() + } + createClusterNetworkAttachmentOptions.SetBefore(beforeModel) + } + if _, ok := d.GetOk("name"); ok { + createClusterNetworkAttachmentOptions.SetName(d.Get("name").(string)) + } + + instanceClusterNetworkAttachment, _, err := vpcClient.CreateClusterNetworkAttachmentWithContext(context, createClusterNetworkAttachmentOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("CreateClusterNetworkAttachmentWithContext failed: %s", err.Error()), "ibm_is_instance_cluster_network_attachment", "create") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(fmt.Sprintf("%s/%s", *createClusterNetworkAttachmentOptions.InstanceID, *instanceClusterNetworkAttachment.ID)) + + return resourceIBMIsInstanceClusterNetworkAttachmentRead(context, d, meta) +} + +func resourceIBMIsInstanceClusterNetworkAttachmentRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_cluster_network_attachment", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + getInstanceClusterNetworkAttachmentOptions := &vpcv1.GetInstanceClusterNetworkAttachmentOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_cluster_network_attachment", "read", "sep-id-parts").GetDiag() + } + + getInstanceClusterNetworkAttachmentOptions.SetInstanceID(parts[0]) + getInstanceClusterNetworkAttachmentOptions.SetID(parts[1]) + + instanceClusterNetworkAttachment, response, err := vpcClient.GetInstanceClusterNetworkAttachmentWithContext(context, getInstanceClusterNetworkAttachmentOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetInstanceClusterNetworkAttachmentWithContext failed: %s", err.Error()), "ibm_is_instance_cluster_network_attachment", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + if !core.IsNil(instanceClusterNetworkAttachment.Before) { + beforeMap, err := ResourceIBMIsInstanceClusterNetworkAttachmentInstanceClusterNetworkAttachmentBeforeToMap(instanceClusterNetworkAttachment.Before) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_cluster_network_attachment", "read", "before-to-map").GetDiag() + } + if err = d.Set("before", []map[string]interface{}{beforeMap}); err != nil { + err = fmt.Errorf("Error setting before: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_cluster_network_attachment", "read", "set-before").GetDiag() + } + } + clusterNetworkInterfaceMap, err := ResourceIBMIsInstanceClusterNetworkAttachmentClusterNetworkInterfaceReferenceToMap(instanceClusterNetworkAttachment.ClusterNetworkInterface) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_cluster_network_attachment", "read", "cluster_network_interface-to-map").GetDiag() + } + if err = d.Set("cluster_network_interface", []map[string]interface{}{clusterNetworkInterfaceMap}); err != nil { + err = fmt.Errorf("Error setting cluster_network_interface: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_cluster_network_attachment", "read", "set-cluster_network_interface").GetDiag() + } + if !core.IsNil(instanceClusterNetworkAttachment.Name) { + if err = d.Set("name", instanceClusterNetworkAttachment.Name); err != nil { + err = fmt.Errorf("Error setting name: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_cluster_network_attachment", "read", "set-name").GetDiag() + } + } + if err = d.Set("href", instanceClusterNetworkAttachment.Href); err != nil { + err = fmt.Errorf("Error setting href: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_cluster_network_attachment", "read", "set-href").GetDiag() + } + lifecycleReasons := []map[string]interface{}{} + for _, lifecycleReasonsItem := range instanceClusterNetworkAttachment.LifecycleReasons { + lifecycleReasonsItemMap, err := ResourceIBMIsInstanceClusterNetworkAttachmentInstanceClusterNetworkAttachmentLifecycleReasonToMap(&lifecycleReasonsItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_cluster_network_attachment", "read", "lifecycle_reasons-to-map").GetDiag() + } + lifecycleReasons = append(lifecycleReasons, lifecycleReasonsItemMap) + } + if err = d.Set("lifecycle_reasons", lifecycleReasons); err != nil { + err = fmt.Errorf("Error setting lifecycle_reasons: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_cluster_network_attachment", "read", "set-lifecycle_reasons").GetDiag() + } + if err = d.Set("lifecycle_state", instanceClusterNetworkAttachment.LifecycleState); err != nil { + err = fmt.Errorf("Error setting lifecycle_state: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_cluster_network_attachment", "read", "set-lifecycle_state").GetDiag() + } + if err = d.Set("resource_type", instanceClusterNetworkAttachment.ResourceType); err != nil { + err = fmt.Errorf("Error setting resource_type: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_cluster_network_attachment", "read", "set-resource_type").GetDiag() + } + if err = d.Set("instance_cluster_network_attachment_id", instanceClusterNetworkAttachment.ID); err != nil { + err = fmt.Errorf("Error setting instance_cluster_network_attachment_id: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_cluster_network_attachment", "read", "set-instance_cluster_network_attachment_id").GetDiag() + } + + return nil +} + +func resourceIBMIsInstanceClusterNetworkAttachmentUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_cluster_network_attachment", "update", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + updateInstanceClusterNetworkAttachmentOptions := &vpcv1.UpdateInstanceClusterNetworkAttachmentOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_cluster_network_attachment", "update", "sep-id-parts").GetDiag() + } + + updateInstanceClusterNetworkAttachmentOptions.SetInstanceID(parts[0]) + updateInstanceClusterNetworkAttachmentOptions.SetID(parts[1]) + + hasChange := false + + patchVals := &vpcv1.InstanceClusterNetworkAttachmentPatch{} + if d.HasChange("instance_id") { + errMsg := fmt.Sprintf("Cannot update resource property \"%s\" with the ForceNew annotation."+ + " The resource must be re-created to update this property.", "instance_id") + return flex.DiscriminatedTerraformErrorf(nil, errMsg, "ibm_is_instance_cluster_network_attachment", "update", "instance_id-forces-new").GetDiag() + } + if d.HasChange("name") { + newName := d.Get("name").(string) + patchVals.Name = &newName + hasChange = true + } + + if hasChange { + // Fields with `nil` values are omitted from the generic map, + // so we need to re-add them to support removing arguments + // in merge-patch operations sent to the service. + updateInstanceClusterNetworkAttachmentOptions.InstanceClusterNetworkAttachmentPatch = ResourceIBMIsInstanceClusterNetworkAttachmentInstanceClusterNetworkAttachmentPatchAsPatch(patchVals, d) + + _, _, err = vpcClient.UpdateInstanceClusterNetworkAttachmentWithContext(context, updateInstanceClusterNetworkAttachmentOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("UpdateInstanceClusterNetworkAttachmentWithContext failed: %s", err.Error()), "ibm_is_instance_cluster_network_attachment", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + } + + return resourceIBMIsInstanceClusterNetworkAttachmentRead(context, d, meta) +} + +func resourceIBMIsInstanceClusterNetworkAttachmentDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := meta.(conns.ClientSession).VpcV1API() + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_cluster_network_attachment", "delete", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + deleteInstanceClusterNetworkAttachmentOptions := &vpcv1.DeleteInstanceClusterNetworkAttachmentOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_cluster_network_attachment", "delete", "sep-id-parts").GetDiag() + } + + deleteInstanceClusterNetworkAttachmentOptions.SetInstanceID(parts[0]) + deleteInstanceClusterNetworkAttachmentOptions.SetID(parts[1]) + + _, _, err = vpcClient.DeleteInstanceClusterNetworkAttachmentWithContext(context, deleteInstanceClusterNetworkAttachmentOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("DeleteInstanceClusterNetworkAttachmentWithContext failed: %s", err.Error()), "ibm_is_instance_cluster_network_attachment", "delete") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId("") + + return nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentMapToInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterface(modelMap map[string]interface{}) (vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceIntf, error) { + model := &vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterface{} + if modelMap["auto_delete"] != nil { + model.AutoDelete = core.BoolPtr(modelMap["auto_delete"].(bool)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["primary_ip"] != nil && len(modelMap["primary_ip"].([]interface{})) > 0 { + PrimaryIPModel, err := ResourceIBMIsInstanceClusterNetworkAttachmentMapToClusterNetworkInterfacePrimaryIPPrototype(modelMap["primary_ip"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.PrimaryIP = PrimaryIPModel + } + if modelMap["subnet"] != nil && len(modelMap["subnet"].([]interface{})) > 0 { + SubnetModel, err := ResourceIBMIsInstanceClusterNetworkAttachmentMapToClusterNetworkSubnetIdentity(modelMap["subnet"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Subnet = SubnetModel + } + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["href"] != nil && modelMap["href"].(string) != "" { + model.Href = core.StringPtr(modelMap["href"].(string)) + } + return model, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentMapToClusterNetworkInterfacePrimaryIPPrototype(modelMap map[string]interface{}) (vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeIntf, error) { + model := &vpcv1.ClusterNetworkInterfacePrimaryIPPrototype{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["href"] != nil && modelMap["href"].(string) != "" { + model.Href = core.StringPtr(modelMap["href"].(string)) + } + if modelMap["address"] != nil && modelMap["address"].(string) != "" { + model.Address = core.StringPtr(modelMap["address"].(string)) + } + if modelMap["auto_delete"] != nil { + model.AutoDelete = core.BoolPtr(modelMap["auto_delete"].(bool)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + return model, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentMapToClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContext(modelMap map[string]interface{}) (vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextIntf, error) { + model := &vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContext{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["href"] != nil && modelMap["href"].(string) != "" { + model.Href = core.StringPtr(modelMap["href"].(string)) + } + return model, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentMapToClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByID(modelMap map[string]interface{}) (*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByID, error) { + model := &vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByID{} + model.ID = core.StringPtr(modelMap["id"].(string)) + return model, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentMapToClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHref(modelMap map[string]interface{}) (*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHref, error) { + model := &vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHref{} + model.Href = core.StringPtr(modelMap["href"].(string)) + return model, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentMapToClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContext(modelMap map[string]interface{}) (*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContext, error) { + model := &vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContext{} + if modelMap["address"] != nil && modelMap["address"].(string) != "" { + model.Address = core.StringPtr(modelMap["address"].(string)) + } + if modelMap["auto_delete"] != nil { + model.AutoDelete = core.BoolPtr(modelMap["auto_delete"].(bool)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + return model, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentMapToClusterNetworkSubnetIdentity(modelMap map[string]interface{}) (vpcv1.ClusterNetworkSubnetIdentityIntf, error) { + model := &vpcv1.ClusterNetworkSubnetIdentity{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["href"] != nil && modelMap["href"].(string) != "" { + model.Href = core.StringPtr(modelMap["href"].(string)) + } + return model, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentMapToClusterNetworkSubnetIdentityByID(modelMap map[string]interface{}) (*vpcv1.ClusterNetworkSubnetIdentityByID, error) { + model := &vpcv1.ClusterNetworkSubnetIdentityByID{} + model.ID = core.StringPtr(modelMap["id"].(string)) + return model, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentMapToClusterNetworkSubnetIdentityByHref(modelMap map[string]interface{}) (*vpcv1.ClusterNetworkSubnetIdentityByHref, error) { + model := &vpcv1.ClusterNetworkSubnetIdentityByHref{} + model.Href = core.StringPtr(modelMap["href"].(string)) + return model, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentMapToInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceInstanceClusterNetworkInterfacePrototypeInstanceClusterNetworkAttachment(modelMap map[string]interface{}) (*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceInstanceClusterNetworkInterfacePrototypeInstanceClusterNetworkAttachment, error) { + model := &vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceInstanceClusterNetworkInterfacePrototypeInstanceClusterNetworkAttachment{} + if modelMap["auto_delete"] != nil { + model.AutoDelete = core.BoolPtr(modelMap["auto_delete"].(bool)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["primary_ip"] != nil && len(modelMap["primary_ip"].([]interface{})) > 0 { + PrimaryIPModel, err := ResourceIBMIsInstanceClusterNetworkAttachmentMapToClusterNetworkInterfacePrimaryIPPrototype(modelMap["primary_ip"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.PrimaryIP = PrimaryIPModel + } + if modelMap["subnet"] != nil && len(modelMap["subnet"].([]interface{})) > 0 { + SubnetModel, err := ResourceIBMIsInstanceClusterNetworkAttachmentMapToClusterNetworkSubnetIdentity(modelMap["subnet"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Subnet = SubnetModel + } + return model, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentMapToInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentity(modelMap map[string]interface{}) (vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityIntf, error) { + model := &vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentity{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["href"] != nil && modelMap["href"].(string) != "" { + model.Href = core.StringPtr(modelMap["href"].(string)) + } + return model, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentMapToInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByID(modelMap map[string]interface{}) (*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByID, error) { + model := &vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByID{} + model.ID = core.StringPtr(modelMap["id"].(string)) + return model, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentMapToInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByHref(modelMap map[string]interface{}) (*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByHref, error) { + model := &vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByHref{} + model.Href = core.StringPtr(modelMap["href"].(string)) + return model, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentMapToInstanceClusterNetworkAttachmentBeforePrototype(modelMap map[string]interface{}) (vpcv1.InstanceClusterNetworkAttachmentBeforePrototypeIntf, error) { + model := &vpcv1.InstanceClusterNetworkAttachmentBeforePrototype{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["href"] != nil && modelMap["href"].(string) != "" { + model.Href = core.StringPtr(modelMap["href"].(string)) + } + return model, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentMapToInstanceClusterNetworkAttachmentBeforePrototypeInstanceClusterNetworkAttachmentIdentityByID(modelMap map[string]interface{}) (*vpcv1.InstanceClusterNetworkAttachmentBeforePrototypeInstanceClusterNetworkAttachmentIdentityByID, error) { + model := &vpcv1.InstanceClusterNetworkAttachmentBeforePrototypeInstanceClusterNetworkAttachmentIdentityByID{} + model.ID = core.StringPtr(modelMap["id"].(string)) + return model, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentMapToInstanceClusterNetworkAttachmentBeforePrototypeInstanceClusterNetworkAttachmentIdentityByHref(modelMap map[string]interface{}) (*vpcv1.InstanceClusterNetworkAttachmentBeforePrototypeInstanceClusterNetworkAttachmentIdentityByHref, error) { + model := &vpcv1.InstanceClusterNetworkAttachmentBeforePrototypeInstanceClusterNetworkAttachmentIdentityByHref{} + model.Href = core.StringPtr(modelMap["href"].(string)) + return model, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentInstanceClusterNetworkAttachmentBeforeToMap(model *vpcv1.InstanceClusterNetworkAttachmentBefore) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["id"] = *model.ID + modelMap["name"] = *model.Name + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentClusterNetworkInterfaceReferenceToMap(model *vpcv1.ClusterNetworkInterfaceReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := ResourceIBMIsInstanceClusterNetworkAttachmentDeletedToMap(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 + primaryIPMap, err := ResourceIBMIsInstanceClusterNetworkAttachmentClusterNetworkSubnetReservedIPReferenceToMap(model.PrimaryIP) + if err != nil { + return modelMap, err + } + modelMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + modelMap["resource_type"] = *model.ResourceType + subnetMap, err := ResourceIBMIsInstanceClusterNetworkAttachmentClusterNetworkSubnetReferenceToMap(model.Subnet) + if err != nil { + return modelMap, err + } + modelMap["subnet"] = []map[string]interface{}{subnetMap} + return modelMap, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentDeletedToMap(model *vpcv1.Deleted) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["more_info"] = *model.MoreInfo + return modelMap, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentClusterNetworkSubnetReservedIPReferenceToMap(model *vpcv1.ClusterNetworkSubnetReservedIPReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["address"] = *model.Address + if model.Deleted != nil { + deletedMap, err := ResourceIBMIsInstanceClusterNetworkAttachmentDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentClusterNetworkSubnetReferenceToMap(model *vpcv1.ClusterNetworkSubnetReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Deleted != nil { + deletedMap, err := ResourceIBMIsInstanceClusterNetworkAttachmentDeletedToMap(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 + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentInstanceClusterNetworkAttachmentLifecycleReasonToMap(model *vpcv1.InstanceClusterNetworkAttachmentLifecycleReason) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["code"] = *model.Code + modelMap["message"] = *model.Message + if model.MoreInfo != nil { + modelMap["more_info"] = *model.MoreInfo + } + return modelMap, nil +} + +func ResourceIBMIsInstanceClusterNetworkAttachmentInstanceClusterNetworkAttachmentPatchAsPatch(patchVals *vpcv1.InstanceClusterNetworkAttachmentPatch, d *schema.ResourceData) map[string]interface{} { + patch, _ := patchVals.AsPatch() + var path string + + path = "name" + if _, exists := d.GetOk(path); d.HasChange(path) && !exists { + patch["name"] = nil + } + + return patch +} diff --git a/ibm/service/vpc/resource_ibm_is_instance_cluster_network_attachment_test.go b/ibm/service/vpc/resource_ibm_is_instance_cluster_network_attachment_test.go new file mode 100644 index 0000000000..289c5e6a9e --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_instance_cluster_network_attachment_test.go @@ -0,0 +1,209 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_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/vpc-go-sdk/vpcv1" +) + +func TestAccIBMIsInstanceClusterNetworkAttachmentBasic(t *testing.T) { + var conf vpcv1.InstanceClusterNetworkAttachment + instanceID := fmt.Sprintf("tf_instance_id_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsInstanceClusterNetworkAttachmentDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsInstanceClusterNetworkAttachmentConfigBasic(instanceID), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsInstanceClusterNetworkAttachmentExists("ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", conf), + resource.TestCheckResourceAttr("ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "instance_id", instanceID), + ), + }, + }, + }) +} + +func TestAccIBMIsInstanceClusterNetworkAttachmentAllArgs(t *testing.T) { + var conf vpcv1.InstanceClusterNetworkAttachment + instanceID := fmt.Sprintf("tf_instance_id_%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + nameUpdate := fmt.Sprintf("tf_name_%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMIsInstanceClusterNetworkAttachmentDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsInstanceClusterNetworkAttachmentConfig(instanceID, name), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMIsInstanceClusterNetworkAttachmentExists("ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", conf), + resource.TestCheckResourceAttr("ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "instance_id", instanceID), + resource.TestCheckResourceAttr("ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "name", name), + ), + }, + resource.TestStep{ + Config: testAccCheckIBMIsInstanceClusterNetworkAttachmentConfig(instanceID, nameUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "instance_id", instanceID), + resource.TestCheckResourceAttr("ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance", "name", nameUpdate), + ), + }, + resource.TestStep{ + ResourceName: "ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckIBMIsInstanceClusterNetworkAttachmentConfigBasic(instanceID string) string { + return fmt.Sprintf(` + resource "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance" { + instance_id = "%s" + cluster_network_interface { + href = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/interfaces/0717-ffc092f7-5d02-4b93-ab69-26860529b9fb" + id = "0717-ffc092f7-5d02-4b93-ab69-26860529b9fb" + name = "my-cluster-network-interface" + primary_ip { + address = "10.1.0.6" + deleted { + more_info = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + } + href = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930/reserved_ips/6d353a0f-aeb1-4ae1-832e-1110d10981bb" + id = "6d353a0f-aeb1-4ae1-832e-1110d10981bb" + name = "my-cluster-network-subnet-reserved-ip" + resource_type = "cluster_network_subnet_reserved_ip" + } + subnet { + deleted { + more_info = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + } + href = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930" + id = "0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930" + name = "my-cluster-network-subnet" + resource_type = "cluster_network_subnet" + } + } + } + `, instanceID) +} + +func testAccCheckIBMIsInstanceClusterNetworkAttachmentConfig(instanceID string, name string) string { + return fmt.Sprintf(` + + resource "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance" { + instance_id = "%s" + before { + href = "https://us-south.iaas.cloud.ibm.com/v1/instances/0717_e21b7391-2ca2-4ab5-84a8-b92157a633b0/cluster_network_attachments/0717-fb880975-db45-4459-8548-64e3995ac213" + id = "0717-fb880975-db45-4459-8548-64e3995ac213" + } + cluster_network_interface { + href = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/interfaces/0717-ffc092f7-5d02-4b93-ab69-26860529b9fb" + id = "0717-ffc092f7-5d02-4b93-ab69-26860529b9fb" + name = "my-cluster-network-interface" + primary_ip { + address = "10.1.0.6" + deleted { + more_info = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + } + href = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930/reserved_ips/6d353a0f-aeb1-4ae1-832e-1110d10981bb" + id = "6d353a0f-aeb1-4ae1-832e-1110d10981bb" + name = "my-cluster-network-subnet-reserved-ip" + resource_type = "cluster_network_subnet_reserved_ip" + } + subnet { + deleted { + more_info = "https://cloud.ibm.com/apidocs/vpc#deleted-resources" + } + href = "https://us-south.iaas.cloud.ibm.com/v1/cluster_networks/0717-da0df18c-7598-4633-a648-fdaac28a5573/subnets/0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930" + id = "0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930" + name = "my-cluster-network-subnet" + resource_type = "cluster_network_subnet" + } + } + name = "%s" + } + `, instanceID, name) +} + +func testAccCheckIBMIsInstanceClusterNetworkAttachmentExists(n string, obj vpcv1.InstanceClusterNetworkAttachment) 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 + } + + getInstanceClusterNetworkAttachmentOptions := &vpcv1.GetInstanceClusterNetworkAttachmentOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getInstanceClusterNetworkAttachmentOptions.SetInstanceID(parts[0]) + getInstanceClusterNetworkAttachmentOptions.SetID(parts[1]) + + instanceClusterNetworkAttachment, _, err := vpcClient.GetInstanceClusterNetworkAttachment(getInstanceClusterNetworkAttachmentOptions) + if err != nil { + return err + } + + obj = *instanceClusterNetworkAttachment + return nil + } +} + +func testAccCheckIBMIsInstanceClusterNetworkAttachmentDestroy(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_instance_cluster_network_attachment" { + continue + } + + getInstanceClusterNetworkAttachmentOptions := &vpcv1.GetInstanceClusterNetworkAttachmentOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getInstanceClusterNetworkAttachmentOptions.SetInstanceID(parts[0]) + getInstanceClusterNetworkAttachmentOptions.SetID(parts[1]) + + // Try to find the key + _, response, err := vpcClient.GetInstanceClusterNetworkAttachment(getInstanceClusterNetworkAttachmentOptions) + + if err == nil { + return fmt.Errorf("InstanceClusterNetworkAttachment still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for InstanceClusterNetworkAttachment (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_instance_template.go b/ibm/service/vpc/resource_ibm_is_instance_template.go index 7a0b0ac2de..f3240f3169 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_template.go +++ b/ibm/service/vpc/resource_ibm_is_instance_template.go @@ -110,6 +110,115 @@ func ResourceIBMISInstanceTemplate() *schema.Resource { Description: "Instance Template name", }, + // cluster changes + "cluster_network_attachments": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Description: "The cluster network attachments to create for this virtual server instance. A cluster network attachment represents a device that is connected to a cluster network. The number of network attachments must match one of the values from the instance profile's `cluster_network_attachment_count` before the instance can be started.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cluster_network_interface": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Required: true, + ForceNew: true, + Description: "A cluster network interface for the instance cluster network attachment. This can bespecified using an existing cluster network interface that does not already have a `target`,or a prototype object for a new cluster network interface.This instance must reside in the same VPC as the specified cluster network interface. Thecluster network interface must reside in the same cluster network as the`cluster_network_interface` of any other `cluster_network_attachments` for this instance.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Indicates whether this cluster network interface will be automatically deleted when `target` is deleted.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The name for this cluster network interface. The name must not be used by another interface in the cluster network. Names beginning with `ibm-` are reserved for provider-owned resources, and are not allowed. If unspecified, the name will be a hyphenated list of randomly-selected words.", + }, + "primary_ip": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "The primary IP address to bind to the cluster network interface. May be eithera cluster network subnet reserved IP identity, or a cluster network subnet reserved IPprototype object which will be used to create a new cluster network subnet reserved IP.If a cluster network subnet reserved IP identity is provided, the specified clusternetwork subnet reserved IP must be unbound.If a cluster network subnet reserved IP prototype object with an address is provided,the address must be available on the cluster network interface's cluster networksubnet. If no address is specified, an available address on the cluster network subnetwill be automatically selected and reserved.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The unique identifier for this cluster network subnet reserved IP.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The URL for this cluster network subnet reserved IP.", + }, + "address": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The IP address to reserve, which must not already be reserved on the subnet.If unspecified, an available address on the subnet will automatically be selected.", + }, + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Indicates whether this cluster network subnet reserved IP member will be automatically deleted when either `target` is deleted, or the cluster network subnet reserved IP is unbound.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The name for this cluster network subnet reserved IP. The name must not be used by another reserved IP in the cluster network subnet. Names starting with `ibm-` are reserved for provider-owned resources, and are not allowed. If unspecified, the name will be a hyphenated list of randomly-selected words.", + }, + }, + }, + }, + "subnet": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "The associated cluster network subnet. Required if `primary_ip` does not specify acluster network subnet reserved IP identity.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The unique identifier for this cluster network subnet.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The URL for this cluster network subnet.", + }, + }, + }, + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The unique identifier for this cluster network interface.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The URL for this cluster network interface.", + }, + }, + }, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The name for this cluster network attachment. Names must be unique within the instance the cluster network attachment resides in. If unspecified, the name will be a hyphenated list of randomly-selected words. Names starting with `ibm-` are reserved for provider-owned resources, and are not allowed.", + }, + }, + }, + }, + "confidential_compute_mode": &schema.Schema{ Type: schema.TypeString, Optional: true, @@ -1278,6 +1387,19 @@ func instanceTemplateCreateByCatalogOffering(d *schema.ResourceData, meta interf ID: &vpcID, }, } + // cluster changes + if clusterNetworkAttachmentOk, ok := d.GetOk("cluster_network_attachments"); ok { + clusterNetworkAttachmentList := clusterNetworkAttachmentOk.([]interface{}) + clusterNetworkAttachments := []vpcv1.InstanceClusterNetworkAttachmentPrototypeInstanceContext{} + for _, clusterNetworkAttachmentsItem := range clusterNetworkAttachmentList { + clusterNetworkAttachmentsItemModel, err := ResourceIBMIsInstanceTemplateMapToInstanceClusterNetworkAttachmentPrototypeInstanceContext(clusterNetworkAttachmentsItem.(map[string]interface{})) + if err != nil { + return err + } + clusterNetworkAttachments = append(clusterNetworkAttachments, *clusterNetworkAttachmentsItemModel) + } + instanceproto.ClusterNetworkAttachments = clusterNetworkAttachments + } if _, ok := d.GetOk("confidential_compute_mode"); ok { instanceproto.ConfidentialComputeMode = core.StringPtr(d.Get("confidential_compute_mode").(string)) } @@ -1767,6 +1889,19 @@ func instanceTemplateCreate(d *schema.ResourceData, meta interface{}, profile, n if name != "" { instanceproto.Name = &name } + // cluster changes + if clusterNetworkAttachmentOk, ok := d.GetOk("cluster_network_attachments"); ok { + clusterNetworkAttachmentList := clusterNetworkAttachmentOk.([]interface{}) + clusterNetworkAttachments := []vpcv1.InstanceClusterNetworkAttachmentPrototypeInstanceContext{} + for _, clusterNetworkAttachmentsItem := range clusterNetworkAttachmentList { + clusterNetworkAttachmentsItemModel, err := ResourceIBMIsInstanceTemplateMapToInstanceClusterNetworkAttachmentPrototypeInstanceContext(clusterNetworkAttachmentsItem.(map[string]interface{})) + if err != nil { + return err + } + clusterNetworkAttachments = append(clusterNetworkAttachments, *clusterNetworkAttachmentsItemModel) + } + instanceproto.ClusterNetworkAttachments = clusterNetworkAttachments + } if _, ok := d.GetOk("confidential_compute_mode"); ok { instanceproto.ConfidentialComputeMode = core.StringPtr(d.Get("confidential_compute_mode").(string)) } @@ -1860,7 +1995,7 @@ func instanceTemplateCreate(d *schema.ResourceData, meta interface{}, profile, n resAffinity.Policy = &policyStr } poolIntf, okPool := resAff[isReservationAffinityPool] - if okPool { + if okPool && poolIntf != nil && poolIntf.([]interface{}) != nil && len(poolIntf.([]interface{})) > 0 { pool := poolIntf.([]interface{})[0].(map[string]interface{}) id, okId := pool["id"] if okId { @@ -2244,6 +2379,19 @@ func instanceTemplateGet(d *schema.ResourceData, meta interface{}, ID string) er if instance.AvailabilityPolicy != nil && instance.AvailabilityPolicy.HostFailure != nil { d.Set(isInstanceTemplateAvailablePolicyHostFailure, instance.AvailabilityPolicy.HostFailure) } + // cluster changes + clusterNetworkAttachments := []map[string]interface{}{} + for _, clusterNetworkAttachmentsItem := range instance.ClusterNetworkAttachments { + clusterNetworkAttachmentsItemMap, err := ResourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeInstanceContextToMap(&clusterNetworkAttachmentsItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "cluster_network_attachments-to-map") + } + clusterNetworkAttachments = append(clusterNetworkAttachments, clusterNetworkAttachmentsItemMap) + } + if err = d.Set("cluster_network_attachments", clusterNetworkAttachments); err != nil { + err = fmt.Errorf("Error setting cluster_network_attachments: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-cluster_network_attachments") + } if !core.IsNil(instance.ConfidentialComputeMode) { if err = d.Set("confidential_compute_mode", instance.ConfidentialComputeMode); err != nil { return fmt.Errorf("Error setting confidential_compute_mode: %s", err) @@ -2896,3 +3044,392 @@ func hashIpsListForInstanceTemplate(v interface{}) int { buf.WriteString(fmt.Sprintf("%s-", a["address"].(string))) return conns.String(buf.String()) } + +func ResourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeInstanceContextToMap(model *vpcv1.InstanceClusterNetworkAttachmentPrototypeInstanceContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + clusterNetworkInterfaceMap, err := ResourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceToMap(model.ClusterNetworkInterface) + if err != nil { + return modelMap, err + } + modelMap["cluster_network_interface"] = []map[string]interface{}{clusterNetworkInterfaceMap} + if model.Name != nil { + modelMap["name"] = *model.Name + } + return modelMap, nil +} + +func ResourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceToMap(model vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceInstanceClusterNetworkInterfacePrototypeInstanceClusterNetworkAttachment); ok { + return ResourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceInstanceClusterNetworkInterfacePrototypeInstanceClusterNetworkAttachmentToMap(model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceInstanceClusterNetworkInterfacePrototypeInstanceClusterNetworkAttachment)) + } else if _, ok := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentity); ok { + return ResourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityToMap(model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentity)) + } else if _, ok := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterface); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterface) + if model.AutoDelete != nil { + modelMap["auto_delete"] = *model.AutoDelete + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.PrimaryIP != nil { + primaryIPMap, err := ResourceIBMIsInstanceTemplateClusterNetworkInterfacePrimaryIPPrototypeToMap(model.PrimaryIP) + if err != nil { + return modelMap, err + } + modelMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + } + if model.Subnet != nil { + subnetMap, err := ResourceIBMIsInstanceTemplateClusterNetworkSubnetIdentityToMap(model.Subnet) + if err != nil { + return modelMap, err + } + modelMap["subnet"] = []map[string]interface{}{subnetMap} + } + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceIntf subtype encountered") + } +} + +func ResourceIBMIsInstanceTemplateClusterNetworkInterfacePrimaryIPPrototypeToMap(model vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContext); ok { + return ResourceIBMIsInstanceTemplateClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextToMap(model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContext)) + } else if _, ok := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContext); ok { + return ResourceIBMIsInstanceTemplateClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContextToMap(model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContext)) + } else if _, ok := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototype); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototype) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + if model.Address != nil { + modelMap["address"] = *model.Address + } + if model.AutoDelete != nil { + modelMap["auto_delete"] = *model.AutoDelete + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeIntf subtype encountered") + } +} + +func ResourceIBMIsInstanceTemplateClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextToMap(model vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByID); ok { + return ResourceIBMIsInstanceTemplateClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByIDToMap(model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByID)) + } else if _, ok := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHref); ok { + return ResourceIBMIsInstanceTemplateClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHrefToMap(model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHref)) + } else if _, ok := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContext); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContext) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextIntf subtype encountered") + } +} + +func ResourceIBMIsInstanceTemplateClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByIDToMap(model *vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByID) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = *model.ID + return modelMap, nil +} + +func ResourceIBMIsInstanceTemplateClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHrefToMap(model *vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHref) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + return modelMap, nil +} + +func ResourceIBMIsInstanceTemplateClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContextToMap(model *vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContext) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Address != nil { + modelMap["address"] = *model.Address + } + if model.AutoDelete != nil { + modelMap["auto_delete"] = *model.AutoDelete + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + return modelMap, nil +} + +func ResourceIBMIsInstanceTemplateClusterNetworkSubnetIdentityToMap(model vpcv1.ClusterNetworkSubnetIdentityIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.ClusterNetworkSubnetIdentityByID); ok { + return ResourceIBMIsInstanceTemplateClusterNetworkSubnetIdentityByIDToMap(model.(*vpcv1.ClusterNetworkSubnetIdentityByID)) + } else if _, ok := model.(*vpcv1.ClusterNetworkSubnetIdentityByHref); ok { + return ResourceIBMIsInstanceTemplateClusterNetworkSubnetIdentityByHrefToMap(model.(*vpcv1.ClusterNetworkSubnetIdentityByHref)) + } else if _, ok := model.(*vpcv1.ClusterNetworkSubnetIdentity); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.ClusterNetworkSubnetIdentity) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.ClusterNetworkSubnetIdentityIntf subtype encountered") + } +} + +func ResourceIBMIsInstanceTemplateClusterNetworkSubnetIdentityByIDToMap(model *vpcv1.ClusterNetworkSubnetIdentityByID) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = *model.ID + return modelMap, nil +} + +func ResourceIBMIsInstanceTemplateClusterNetworkSubnetIdentityByHrefToMap(model *vpcv1.ClusterNetworkSubnetIdentityByHref) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + return modelMap, nil +} + +func ResourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceInstanceClusterNetworkInterfacePrototypeInstanceClusterNetworkAttachmentToMap(model *vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceInstanceClusterNetworkInterfacePrototypeInstanceClusterNetworkAttachment) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.AutoDelete != nil { + modelMap["auto_delete"] = *model.AutoDelete + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.PrimaryIP != nil { + primaryIPMap, err := ResourceIBMIsInstanceTemplateClusterNetworkInterfacePrimaryIPPrototypeToMap(model.PrimaryIP) + if err != nil { + return modelMap, err + } + modelMap["primary_ip"] = []map[string]interface{}{primaryIPMap} + } + if model.Subnet != nil { + subnetMap, err := ResourceIBMIsInstanceTemplateClusterNetworkSubnetIdentityToMap(model.Subnet) + if err != nil { + return modelMap, err + } + modelMap["subnet"] = []map[string]interface{}{subnetMap} + } + return modelMap, nil +} + +func ResourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityToMap(model vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityIntf) (map[string]interface{}, error) { + if _, ok := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByID); ok { + return ResourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByIDToMap(model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByID)) + } else if _, ok := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByHref); ok { + return ResourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByHrefToMap(model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByHref)) + } else if _, ok := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentity); ok { + modelMap := make(map[string]interface{}) + model := model.(*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentity) + if model.ID != nil { + modelMap["id"] = *model.ID + } + if model.Href != nil { + modelMap["href"] = *model.Href + } + return modelMap, nil + } else { + return nil, fmt.Errorf("Unrecognized vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityIntf subtype encountered") + } +} + +func ResourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByIDToMap(model *vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByID) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["id"] = *model.ID + return modelMap, nil +} + +func ResourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByHrefToMap(model *vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByHref) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + return modelMap, nil +} + +func ResourceIBMIsInstanceTemplateMapToInstanceClusterNetworkAttachmentPrototypeInstanceContext(modelMap map[string]interface{}) (*vpcv1.InstanceClusterNetworkAttachmentPrototypeInstanceContext, error) { + model := &vpcv1.InstanceClusterNetworkAttachmentPrototypeInstanceContext{} + ClusterNetworkInterfaceModel, err := ResourceIBMIsInstanceTemplateMapToInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterface(modelMap["cluster_network_interface"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.ClusterNetworkInterface = ClusterNetworkInterfaceModel + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + return model, nil +} + +func ResourceIBMIsInstanceTemplateMapToInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterface(modelMap map[string]interface{}) (vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceIntf, error) { + model := &vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterface{} + if modelMap["auto_delete"] != nil { + model.AutoDelete = core.BoolPtr(modelMap["auto_delete"].(bool)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["primary_ip"] != nil && len(modelMap["primary_ip"].([]interface{})) > 0 { + PrimaryIPModel, err := ResourceIBMIsInstanceTemplateMapToClusterNetworkInterfacePrimaryIPPrototype(modelMap["primary_ip"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.PrimaryIP = PrimaryIPModel + } + if modelMap["subnet"] != nil && len(modelMap["subnet"].([]interface{})) > 0 { + SubnetModel, err := ResourceIBMIsInstanceTemplateMapToClusterNetworkSubnetIdentity(modelMap["subnet"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Subnet = SubnetModel + } + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["href"] != nil && modelMap["href"].(string) != "" { + model.Href = core.StringPtr(modelMap["href"].(string)) + } + return model, nil +} + +func ResourceIBMIsInstanceTemplateMapToClusterNetworkInterfacePrimaryIPPrototype(modelMap map[string]interface{}) (vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeIntf, error) { + model := &vpcv1.ClusterNetworkInterfacePrimaryIPPrototype{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["href"] != nil && modelMap["href"].(string) != "" { + model.Href = core.StringPtr(modelMap["href"].(string)) + } + if modelMap["address"] != nil && modelMap["address"].(string) != "" { + model.Address = core.StringPtr(modelMap["address"].(string)) + } + if modelMap["auto_delete"] != nil { + model.AutoDelete = core.BoolPtr(modelMap["auto_delete"].(bool)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + return model, nil +} + +func ResourceIBMIsInstanceTemplateMapToClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContext(modelMap map[string]interface{}) (vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextIntf, error) { + model := &vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContext{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["href"] != nil && modelMap["href"].(string) != "" { + model.Href = core.StringPtr(modelMap["href"].(string)) + } + return model, nil +} + +func ResourceIBMIsInstanceTemplateMapToClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByID(modelMap map[string]interface{}) (*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByID, error) { + model := &vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByID{} + model.ID = core.StringPtr(modelMap["id"].(string)) + return model, nil +} + +func ResourceIBMIsInstanceTemplateMapToClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHref(modelMap map[string]interface{}) (*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHref, error) { + model := &vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPIdentityClusterNetworkInterfacePrimaryIPContextByHref{} + model.Href = core.StringPtr(modelMap["href"].(string)) + return model, nil +} + +func ResourceIBMIsInstanceTemplateMapToClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContext(modelMap map[string]interface{}) (*vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContext, error) { + model := &vpcv1.ClusterNetworkInterfacePrimaryIPPrototypeClusterNetworkSubnetReservedIPPrototypeClusterNetworkInterfacePrimaryIPContext{} + if modelMap["address"] != nil && modelMap["address"].(string) != "" { + model.Address = core.StringPtr(modelMap["address"].(string)) + } + if modelMap["auto_delete"] != nil { + model.AutoDelete = core.BoolPtr(modelMap["auto_delete"].(bool)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + return model, nil +} + +func ResourceIBMIsInstanceTemplateMapToClusterNetworkSubnetIdentity(modelMap map[string]interface{}) (vpcv1.ClusterNetworkSubnetIdentityIntf, error) { + model := &vpcv1.ClusterNetworkSubnetIdentity{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["href"] != nil && modelMap["href"].(string) != "" { + model.Href = core.StringPtr(modelMap["href"].(string)) + } + return model, nil +} + +func ResourceIBMIsInstanceTemplateMapToClusterNetworkSubnetIdentityByID(modelMap map[string]interface{}) (*vpcv1.ClusterNetworkSubnetIdentityByID, error) { + model := &vpcv1.ClusterNetworkSubnetIdentityByID{} + model.ID = core.StringPtr(modelMap["id"].(string)) + return model, nil +} + +func ResourceIBMIsInstanceTemplateMapToClusterNetworkSubnetIdentityByHref(modelMap map[string]interface{}) (*vpcv1.ClusterNetworkSubnetIdentityByHref, error) { + model := &vpcv1.ClusterNetworkSubnetIdentityByHref{} + model.Href = core.StringPtr(modelMap["href"].(string)) + return model, nil +} + +func ResourceIBMIsInstanceTemplateMapToInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceInstanceClusterNetworkInterfacePrototypeInstanceClusterNetworkAttachment(modelMap map[string]interface{}) (*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceInstanceClusterNetworkInterfacePrototypeInstanceClusterNetworkAttachment, error) { + model := &vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceInstanceClusterNetworkInterfacePrototypeInstanceClusterNetworkAttachment{} + if modelMap["auto_delete"] != nil { + model.AutoDelete = core.BoolPtr(modelMap["auto_delete"].(bool)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["primary_ip"] != nil && len(modelMap["primary_ip"].([]interface{})) > 0 { + PrimaryIPModel, err := ResourceIBMIsInstanceTemplateMapToClusterNetworkInterfacePrimaryIPPrototype(modelMap["primary_ip"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.PrimaryIP = PrimaryIPModel + } + if modelMap["subnet"] != nil && len(modelMap["subnet"].([]interface{})) > 0 { + SubnetModel, err := ResourceIBMIsInstanceTemplateMapToClusterNetworkSubnetIdentity(modelMap["subnet"].([]interface{})[0].(map[string]interface{})) + if err != nil { + return model, err + } + model.Subnet = SubnetModel + } + return model, nil +} + +func ResourceIBMIsInstanceTemplateMapToInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentity(modelMap map[string]interface{}) (vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityIntf, error) { + model := &vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentity{} + if modelMap["id"] != nil && modelMap["id"].(string) != "" { + model.ID = core.StringPtr(modelMap["id"].(string)) + } + if modelMap["href"] != nil && modelMap["href"].(string) != "" { + model.Href = core.StringPtr(modelMap["href"].(string)) + } + return model, nil +} + +func ResourceIBMIsInstanceTemplateMapToInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByID(modelMap map[string]interface{}) (*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByID, error) { + model := &vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByID{} + model.ID = core.StringPtr(modelMap["id"].(string)) + return model, nil +} + +func ResourceIBMIsInstanceTemplateMapToInstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByHref(modelMap map[string]interface{}) (*vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByHref, error) { + model := &vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterfaceClusterNetworkInterfaceIdentityClusterNetworkInterfaceIdentityByHref{} + model.Href = core.StringPtr(modelMap["href"].(string)) + return model, nil +} diff --git a/ibm/service/vpc/resource_ibm_is_instance_template_test.go b/ibm/service/vpc/resource_ibm_is_instance_template_test.go index 4d819dc180..0bbefa10a2 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_template_test.go +++ b/ibm/service/vpc/resource_ibm_is_instance_template_test.go @@ -939,3 +939,160 @@ func testAccCheckIBMISInstanceTemplateConfigAvailablePolicyHostFailure_Updated(v `, vpcName, subnetName, sshKeyName, publicKey, templateName) } + +func TestAccIBMISInstanceTemplate_clusternetworkbasic(t *testing.T) { + randInt := acctest.RandIntRange(10, 100) + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + clustersubnetname := fmt.Sprintf("tf-clustersubnet-%d", acctest.RandIntRange(10, 100)) + clustersubnetreservedipname := fmt.Sprintf("tf-clustersubnet-reservedip-%d", acctest.RandIntRange(10, 100)) + clusterinterfacename := fmt.Sprintf("tf-clusterinterface-%d", acctest.RandIntRange(10, 100)) + + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDVtuCfWKVGKaRmaRG6JQZY8YdxnDgGzVOK93IrV9R5Hl0JP1oiLLWlZQS2reAKb8lBqyDVEREpaoRUDjqDqXG8J/kR42FKN51su914pjSBc86wJ02VtT1Wm1zRbSg67kT+g8/T1jCgB5XBODqbcICHVP8Z1lXkgbiHLwlUrbz6OZkGJHo/M/kD1Eme8lctceIYNz/Ilm7ewMXZA4fsidpto9AjyarrJLufrOBl4MRVcZTDSJ7rLP982aHpu9pi5eJAjOZc7Og7n4ns3NFppiCwgVMCVUQbN5GBlWhZ1OsT84ZiTf+Zy8ew+Yg5T7Il8HuC7loWnz+esQPf0s3xhC/kTsGgZreIDoh/rxJfD67wKXetNSh5RH/n5BqjaOuXPFeNXmMhKlhj9nJ8scayx/wsvOGuocEIkbyJSLj3sLUU403OafgatEdnJOwbqg6rUNNF5RIjpJpL7eEWlKIi1j9LyhmPJ+fEO7TmOES82VpCMHpLbe4gf/MhhJ/Xy8DKh9s= root@ffd8363b1226 + `) + subnetName := fmt.Sprintf("tf-testsubnet%d", randInt) + templateName := fmt.Sprintf("tf-testtemplate%d", randInt) + sshKeyName := fmt.Sprintf("tf-testsshkey%d", randInt) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceTemplateClusterNetworkConfig(vpcname, clustersubnetname, clustersubnetreservedipname, clusterinterfacename, subnetName, sshKeyName, publicKey, templateName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("ibm_is_vpc.is_vpc", "name", vpcname), + resource.TestCheckResourceAttrSet("ibm_is_vpc.is_vpc", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "id"), + resource.TestCheckResourceAttr("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "name", clustersubnetname), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "id"), + resource.TestCheckResourceAttr("ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "name", clustersubnetreservedipname), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "id"), + resource.TestCheckResourceAttr("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "name", clusterinterfacename), + resource.TestCheckResourceAttrSet("ibm_is_subnet.is_subnet", "id"), + resource.TestCheckResourceAttr("ibm_is_subnet.is_subnet", "name", subnetName), + resource.TestCheckResourceAttrSet("ibm_is_ssh_key.is_sshkey", "id"), + resource.TestCheckResourceAttr("ibm_is_ssh_key.is_sshkey", "name", sshKeyName), + resource.TestCheckResourceAttr( + "ibm_is_instance_template.is_instance_template", "name", templateName), + resource.TestCheckResourceAttrSet("ibm_is_instance_template.is_instance_template", "profile"), + resource.TestCheckResourceAttrSet("ibm_is_instance_template.is_instance_template", "crn"), + resource.TestCheckResourceAttrSet("ibm_is_instance_template.is_instance_template", "image"), + resource.TestCheckResourceAttrSet("ibm_is_instance_template.is_instance_template", "keys.#"), + resource.TestCheckResourceAttrSet("ibm_is_instance_template.is_instance_template", "name"), + resource.TestCheckResourceAttrSet("ibm_is_instance_template.is_instance_template", "resource_group"), + resource.TestCheckResourceAttrSet("ibm_is_instance_template.is_instance_template", "vpc"), + resource.TestCheckResourceAttrSet("ibm_is_instance_template.is_instance_template", "zone"), + resource.TestCheckResourceAttrSet("ibm_is_instance_template.is_instance_template", "boot_volume.#"), + resource.TestCheckResourceAttrSet("ibm_is_instance_template.is_instance_template", "cluster_network_attachments.#"), + resource.TestCheckResourceAttr("ibm_is_instance_template.is_instance_template", "cluster_network_attachments.#", "8"), + ), + }, + }, + }) +} + +func testAccCheckIBMISInstanceTemplateClusterNetworkConfig(vpcname, clustersubnetname, clustersubnetreservedipname, clusternetworkinterfacename, subnetName, sshKeyName, publicKey, templateName string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "is_vpc" { + name = "%s" + } + resource "ibm_is_cluster_network" "is_cluster_network_instance" { + profile = "%s" + vpc { + id = ibm_is_vpc.is_vpc.id + } + zone = "%s" + } + resource "ibm_is_cluster_network_subnet" "is_cluster_network_subnet_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + name = "%s" + total_ipv4_address_count = 64 + } + resource "ibm_is_cluster_network_subnet_reserved_ip" "is_cluster_network_subnet_reserved_ip_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + cluster_network_subnet_id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + address = "${replace(ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.ipv4_cidr_block, "0/26", "11")}" + name = "%s" + } + resource "ibm_is_cluster_network_interface" "is_cluster_network_interface_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + name = "%s" + primary_ip { + id = ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance.cluster_network_subnet_reserved_ip_id + } + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + + resource "ibm_is_subnet" "is_subnet" { + name = "%s" + vpc = ibm_is_vpc.is_vpc.id + zone = "%s" + total_ipv4_address_count = 64 + } + + resource "ibm_is_ssh_key" "is_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance_template" "is_instance_template" { + name = "%s" + image = "%s" + profile = "%s" + + primary_network_interface { + subnet = ibm_is_subnet.is_subnet.id + } + cluster_network_attachments { + cluster_network_interface{ + id = ibm_is_cluster_network_interface.is_cluster_network_interface_instance.cluster_network_interface_id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = ibm_is_cluster_network_interface.is_cluster_network_interface_instance.cluster_network_interface_id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = ibm_is_cluster_network_interface.is_cluster_network_interface_instance.cluster_network_interface_id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = ibm_is_cluster_network_interface.is_cluster_network_interface_instance.cluster_network_interface_id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = ibm_is_cluster_network_interface.is_cluster_network_interface_instance.cluster_network_interface_id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = ibm_is_cluster_network_interface.is_cluster_network_interface_instance.cluster_network_interface_id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = ibm_is_cluster_network_interface.is_cluster_network_interface_instance.cluster_network_interface_id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = ibm_is_cluster_network_interface.is_cluster_network_interface_instance.cluster_network_interface_id + } + } + vpc = ibm_is_vpc.is_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.is_sshkey.id] + } + + + `, vpcname, acc.ISClusterNetworkProfileName, acc.ISZoneName, clustersubnetname, clustersubnetreservedipname, clusternetworkinterfacename, subnetName, acc.ISZoneName, sshKeyName, publicKey, templateName, acc.IsImage, acc.ISInstanceGPUProfileName, acc.ISZoneName) + +} diff --git a/ibm/service/vpc/resource_ibm_is_instance_test.go b/ibm/service/vpc/resource_ibm_is_instance_test.go index f11dcbc6d4..0d84a35495 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_test.go +++ b/ibm/service/vpc/resource_ibm_is_instance_test.go @@ -971,7 +971,7 @@ func TestAccIBMISInstance_basicwithipv4(t *testing.T) { ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR `) sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) - ipv4address := "10.240.0.6" + ipv4address := acc.ISIPV4Address resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, @@ -3014,3 +3014,554 @@ func testAccCheckIBMISInstanceCatalogImagePNAConfig(vpcname, subnetname, sshname } }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.InstanceProfileName, userData, acc.ISZoneName) } + +func TestAccIBMISInstance_volprototypes(t *testing.T) { + var instance string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%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)) + userData1 := "a" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceVolumePrototypesConfig(vpcname, subnetname, sshname, publicKey, name, userData1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "user_data", userData1), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "vcpu.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "vcpu.0.manufacturer"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "volume_prototypes.#"), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "volume_prototypes.#", "5"), + ), + }, + { + Config: testAccCheckIBMISInstanceVolumePrototypesUpdate1Config(vpcname, subnetname, sshname, publicKey, name, userData1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "user_data", userData1), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "primary_network_interface.0.port_speed"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "vcpu.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "vcpu.0.manufacturer"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "numa_count"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "volume_prototypes.#"), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "volume_prototypes.#", "6"), + ), + }, + { + Config: testAccCheckIBMISInstanceVolumePrototypesUpdate2Config(vpcname, subnetname, sshname, publicKey, name, userData1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "user_data", userData1), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "primary_network_interface.0.port_speed"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "vcpu.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "vcpu.0.manufacturer"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "numa_count"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "volume_prototypes.#"), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "volume_prototypes.#", "4"), + ), + }, + }, + }) +} + +func testAccCheckIBMISInstanceVolumePrototypesConfig(vpcname, subnetname, sshname, publicKey, name, userData 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" + ipv4_cidr_block = "%s" + } + + 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 + } + user_data = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + boot_volume { + size = 250 + profile = "sdp" + iops = 10000 + } + volume_prototypes{ + name = "proto1" + delete_volume_on_instance_delete = true + volume_name = "proto1" + volume_capacity = 141 + volume_profile = "sdp" + } + volume_prototypes{ + name = "proto2" + delete_volume_on_instance_delete = true + volume_name = "proto2" + volume_capacity = 142 + volume_profile = "sdp" + } + volume_prototypes{ + name = "proto3" + delete_volume_on_instance_delete = true + volume_name = "proto3" + volume_profile = "general-purpose" + volume_capacity = 143 + } + volume_prototypes{ + name = "proto4" + delete_volume_on_instance_delete = true + volume_name = "proto4" + volume_capacity = 144 + volume_iops = 10000 + volume_profile = "sdp" + } + + volume_prototypes{ + name = "proto5" + delete_volume_on_instance_delete = true + volume_name = "proto55" + volume_capacity = 1455 + volume_profile = "sdp" + } + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, userData, acc.ISZoneName) +} +func testAccCheckIBMISInstanceVolumePrototypesUpdate1Config(vpcname, subnetname, sshname, publicKey, name, userData 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" + ipv4_cidr_block = "%s" + } + + 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 + } + user_data = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + boot_volume { + size = 250 + profile = "sdp" + iops = 10000 + } + volume_prototypes{ + name = "proto1" + delete_volume_on_instance_delete = true + volume_name = "proto1" + volume_capacity = 141 + # volume_iops = 1000 + # volume_profile = "general-purpose" + volume_profile = "sdp" + } + volume_prototypes{ + name = "proto2" + delete_volume_on_instance_delete = true + volume_name = "proto2" + volume_capacity = 142 + # volume_iops = 1000 + # volume_profile = "general-purpose" + volume_profile = "sdp" + } + volume_prototypes{ + name = "proto3" + delete_volume_on_instance_delete = true + volume_name = "proto3" + volume_capacity = 143 + # volume_iops = 1000 + volume_profile = "general-purpose" + # volume_profile = "5iops-tier" + # volume_profile = "sdp" + } + volume_prototypes{ + name = "proto4" + delete_volume_on_instance_delete = true + volume_name = "proto4" + volume_capacity = 144 + volume_iops = 10000 + # volume_profile = "general-purpose" + volume_profile = "sdp" + } + + + volume_prototypes{ + name = "proto5" + delete_volume_on_instance_delete = true + volume_name = "proto55" + volume_capacity = 1455 + # volume_iops = 1000 + # volume_profile = "general-purpose" + volume_profile = "sdp" + } + volume_prototypes{ + name = "proto6" + delete_volume_on_instance_delete = true + volume_name = "proto6" + volume_capacity = 146 + volume_iops = 1000 + # volume_profile = "general-purpose" + volume_profile = "sdp" + } + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, userData, acc.ISZoneName) +} +func testAccCheckIBMISInstanceVolumePrototypesUpdate2Config(vpcname, subnetname, sshname, publicKey, name, userData 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" + ipv4_cidr_block = "%s" + } + + 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 + } + user_data = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + boot_volume { + size = 250 + profile = "sdp" + iops = 10000 + } + volume_prototypes{ + name = "proto1" + delete_volume_on_instance_delete = true + volume_name = "proto1" + volume_capacity = 141 + # volume_iops = 1000 + # volume_profile = "general-purpose" + volume_profile = "sdp" + } + volume_prototypes{ + name = "proto2" + delete_volume_on_instance_delete = true + volume_name = "proto2" + volume_capacity = 142 + # volume_iops = 1000 + # volume_profile = "general-purpose" + volume_profile = "sdp" + } + volume_prototypes{ + name = "proto3" + delete_volume_on_instance_delete = true + volume_name = "proto3" + volume_capacity = 143 + # volume_iops = 1000 + volume_profile = "general-purpose" + # volume_profile = "5iops-tier" + # volume_profile = "sdp" + } + volume_prototypes{ + name = "proto4" + delete_volume_on_instance_delete = true + volume_name = "proto4" + volume_capacity = 144 + volume_iops = 10000 + # volume_profile = "general-purpose" + volume_profile = "sdp" + } + }`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, userData, acc.ISZoneName) +} + +// cluster changes + +func TestAccIBMISInstanceclusternetworkattachment_basic(t *testing.T) { + var instance string + randInt := acctest.RandIntRange(10, 100) + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + clustersubnetname := fmt.Sprintf("tf-clustersubnet-%d", acctest.RandIntRange(10, 100)) + clustersubnetreservedipname := fmt.Sprintf("tf-clustersubnet-reservedip-%d", acctest.RandIntRange(10, 100)) + clusterinterfacename := fmt.Sprintf("tf-clusterinterface-%d", acctest.RandIntRange(10, 100)) + + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDVtuCfWKVGKaRmaRG6JQZY8YdxnDgGzVOK93IrV9R5Hl0JP1oiLLWlZQS2reAKb8lBqyDVEREpaoRUDjqDqXG8J/kR42FKN51su914pjSBc86wJ02VtT1Wm1zRbSg67kT+g8/T1jCgB5XBODqbcICHVP8Z1lXkgbiHLwlUrbz6OZkGJHo/M/kD1Eme8lctceIYNz/Ilm7ewMXZA4fsidpto9AjyarrJLufrOBl4MRVcZTDSJ7rLP982aHpu9pi5eJAjOZc7Og7n4ns3NFppiCwgVMCVUQbN5GBlWhZ1OsT84ZiTf+Zy8ew+Yg5T7Il8HuC7loWnz+esQPf0s3xhC/kTsGgZreIDoh/rxJfD67wKXetNSh5RH/n5BqjaOuXPFeNXmMhKlhj9nJ8scayx/wsvOGuocEIkbyJSLj3sLUU403OafgatEdnJOwbqg6rUNNF5RIjpJpL7eEWlKIi1j9LyhmPJ+fEO7TmOES82VpCMHpLbe4gf/MhhJ/Xy8DKh9s= root@ffd8363b1226 + `) + subnetName := fmt.Sprintf("tf-testsubnet-%d", randInt) + name := fmt.Sprintf("tf-testinstance-%d", randInt) + updatedname := fmt.Sprintf("tf-testinstance-%d", randInt) + sshKeyName := fmt.Sprintf("tf-testsshkey-%d", randInt) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceClusterNetworkAttachmentConfig(vpcname, clustersubnetname, clustersubnetreservedipname, clusterinterfacename, subnetName, sshKeyName, publicKey, name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.is_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.is_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.is_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.is_instance", "vcpu.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.is_instance", "vcpu.0.manufacturer"), + resource.TestCheckResourceAttr("ibm_is_vpc.is_vpc", "name", vpcname), + resource.TestCheckResourceAttrSet("ibm_is_vpc.is_vpc", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network.is_cluster_network_instance", "id"), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "id"), + resource.TestCheckResourceAttr("ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance", "name", clustersubnetname), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "id"), + resource.TestCheckResourceAttr("ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance", "name", clustersubnetreservedipname), + resource.TestCheckResourceAttrSet("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "id"), + resource.TestCheckResourceAttr("ibm_is_cluster_network_interface.is_cluster_network_interface_instance", "name", clusterinterfacename), + resource.TestCheckResourceAttrSet("ibm_is_subnet.is_subnet", "id"), + resource.TestCheckResourceAttr("ibm_is_subnet.is_subnet", "name", subnetName), + resource.TestCheckResourceAttrSet("ibm_is_ssh_key.is_sshkey", "id"), + resource.TestCheckResourceAttr("ibm_is_ssh_key.is_sshkey", "name", sshKeyName), + resource.TestCheckResourceAttr( + "ibm_is_instance.is_instance", "name", name), + resource.TestCheckResourceAttrSet("ibm_is_instance.is_instance", "profile"), + resource.TestCheckResourceAttrSet("ibm_is_instance.is_instance", "crn"), + resource.TestCheckResourceAttrSet("ibm_is_instance.is_instance", "image"), + resource.TestCheckResourceAttrSet("ibm_is_instance.is_instance", "keys.#"), + resource.TestCheckResourceAttrSet("ibm_is_instance.is_instance", "name"), + resource.TestCheckResourceAttrSet("ibm_is_instance.is_instance", "resource_group"), + resource.TestCheckResourceAttrSet("ibm_is_instance.is_instance", "vpc"), + resource.TestCheckResourceAttrSet("ibm_is_instance.is_instance", "zone"), + resource.TestCheckResourceAttrSet("ibm_is_instance.is_instance", "boot_volume.#"), + resource.TestCheckResourceAttrSet("ibm_is_instance.is_instance", "cluster_network_attachments.#"), + resource.TestCheckResourceAttr("ibm_is_instance.is_instance", "cluster_network_attachments.#", "8"), + ), + }, + { + Config: testAccCheckIBMISInstanceClusterNetworkAttachmentConfig(vpcname, clustersubnetname, clustersubnetreservedipname, clusterinterfacename, subnetName, sshKeyName, publicKey, updatedname), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "zone", acc.ISZoneName), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "primary_network_interface.0.port_speed"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "vcpu.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "vcpu.0.manufacturer"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance", "numa_count"), + ), + }, + }, + }) +} + +func testAccCheckIBMISInstanceClusterNetworkAttachmentConfig(vpcname, clustersubnetname, clustersubnetreservedipname, clusternetworkinterfacename, subnetName, sshKeyName, publicKey, instanceName string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "is_vpc" { + name = "%s" + } + resource "ibm_is_cluster_network" "is_cluster_network_instance" { + profile = "%s" + vpc { + id = ibm_is_vpc.is_vpc.id + } + zone = "%s" + } + resource "ibm_is_cluster_network_subnet" "is_cluster_network_subnet_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + name = "%s" + total_ipv4_address_count = 64 + } + resource "ibm_is_cluster_network_subnet_reserved_ip" "is_cluster_network_subnet_reserved_ip_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + cluster_network_subnet_id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + address = "${replace(ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.ipv4_cidr_block, "0/26", "11")}" + name = "%s" + } + resource "ibm_is_cluster_network_interface" "is_cluster_network_interface_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + name = "%s" + primary_ip { + id = ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance.cluster_network_subnet_reserved_ip_id + } + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + + resource "ibm_is_subnet" "is_subnet" { + name = "%s" + vpc = ibm_is_vpc.is_vpc.id + zone = "%s" + total_ipv4_address_count = 64 + } + + resource "ibm_is_ssh_key" "is_sshkey" { + name = "%s" + public_key = "%s" + } + resource "ibm_is_instance" "is_instance" { + name = "%s" + image = "%s" + profile = "%s" + timeouts { + create = "60m" + } + primary_network_attachment { + name = "my-pna" + virtual_network_interface { + auto_delete = true + subnet = ibm_is_subnet.is_subnet.id + } + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-1" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-2" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-3" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-4" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-5" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-6" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-7" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-8" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + vpc = ibm_is_vpc.is_vpc.id + zone = ibm_is_subnet.is_subnet.zone + keys = [ibm_is_ssh_key.is_sshkey.id] + } + `, vpcname, acc.ISClusterNetworkProfileName, acc.ISZoneName, clustersubnetname, clustersubnetreservedipname, clusternetworkinterfacename, subnetName, acc.ISZoneName, sshKeyName, publicKey, instanceName, acc.IsImage, acc.ISInstanceGPUProfileName) +} diff --git a/ibm/service/vpc/resource_ibm_is_reservation.go b/ibm/service/vpc/resource_ibm_is_reservation.go index 0d98ac3520..d9835590e5 100644 --- a/ibm/service/vpc/resource_ibm_is_reservation.go +++ b/ibm/service/vpc/resource_ibm_is_reservation.go @@ -264,9 +264,9 @@ func ResourceIBMISReservation() *schema.Resource { func ResourceIBMISReservationValidator() *validate.ResourceValidator { validateSchema := make([]validate.ValidateSchema, 0) - affinityPolicy := "restricted" - term := "one_year,three_year" - resourceType := "instance_profile" + affinityPolicy := "automatic, restricted" + term := "one_year, three_year" + resourceType := "bare_metal_server_profile, instance_profile" validateSchema = append(validateSchema, validate.ValidateSchema{ @@ -504,7 +504,7 @@ func resourceIBMISReservationRead(d *schema.ResourceData, meta interface{}) erro profileMap := []map[string]interface{}{} finalList := map[string]interface{}{} - profileItem := reservation.Profile + profileItem := reservation.Profile.(*vpcv1.ReservationProfile) if profileItem.Href != nil { finalList[isReservationProfileHref] = profileItem.Href @@ -576,6 +576,7 @@ func resourceIBMISReservationUpdate(d *schema.ResourceData, meta interface{}) er } hasChanged := false name := "" + affPol := "" reservationPatchModel := &vpcv1.ReservationPatch{} if d.HasChange(isReservationName) { @@ -585,6 +586,13 @@ func resourceIBMISReservationUpdate(d *schema.ResourceData, meta interface{}) er hasChanged = true } } + if d.HasChange(isReservationAffinityPolicy) { + affPol = d.Get(isReservationAffinityPolicy).(string) + if affPol != "" { + reservationPatchModel.AffinityPolicy = &affPol + hasChanged = true + } + } if d.HasChange(isReservationCapacity) { capacityIntf := d.Get(isReservationCapacity) capacityMap := capacityIntf.([]interface{})[0].(map[string]interface{}) @@ -593,6 +601,7 @@ func resourceIBMISReservationUpdate(d *schema.ResourceData, meta interface{}) er reservationPatchModel.Capacity = &vpcv1.ReservationCapacityPatch{ Total: core.Int64Ptr(int64(totalIntf.(int))), } + hasChanged = true } } } @@ -605,12 +614,14 @@ func resourceIBMISReservationUpdate(d *schema.ResourceData, meta interface{}) er if expPolIntf.(string) != "" { cuPatch.ExpirationPolicy = core.StringPtr(string(expPolIntf.(string))) } + hasChanged = true } } if d.HasChange(isReservationCommittedUse + ".0." + isReservationComittedUseTerm) { if termIntf, ok := committedUseMap[isReservationComittedUseTerm]; ok { cuPatch.Term = core.StringPtr(string(termIntf.(string))) } + hasChanged = true } reservationPatchModel.CommittedUse = cuPatch } @@ -623,6 +634,7 @@ func resourceIBMISReservationUpdate(d *schema.ResourceData, meta interface{}) er if profNameIntf.(string) != "" { profPatch.Name = core.StringPtr(string(profNameIntf.(string))) } + hasChanged = true } } if d.HasChange(isReservationProfile + ".0." + isReservationProfileResourceType) { @@ -630,6 +642,7 @@ func resourceIBMISReservationUpdate(d *schema.ResourceData, meta interface{}) er if resTypeIntf.(string) != "" { profPatch.ResourceType = core.StringPtr(string(resTypeIntf.(string))) } + hasChanged = true } } reservationPatchModel.Profile = profPatch diff --git a/ibm/service/vpc/resource_ibm_is_reservation_activate.go b/ibm/service/vpc/resource_ibm_is_reservation_activate.go index 96ac3c4753..8379f63eb8 100644 --- a/ibm/service/vpc/resource_ibm_is_reservation_activate.go +++ b/ibm/service/vpc/resource_ibm_is_reservation_activate.go @@ -350,7 +350,7 @@ func resourceIBMISReservationActivateRead(d *schema.ResourceData, meta interface profileMap := []map[string]interface{}{} finalList := map[string]interface{}{} - profileItem := reservation.Profile + profileItem := reservation.Profile.(*vpcv1.ReservationProfile) if profileItem.Href != nil { finalList[isReservationProfileHref] = profileItem.Href diff --git a/ibm/service/vpc/resource_ibm_is_volume.go b/ibm/service/vpc/resource_ibm_is_volume.go index 210437396b..2549aebded 100644 --- a/ibm/service/vpc/resource_ibm_is_volume.go +++ b/ibm/service/vpc/resource_ibm_is_volume.go @@ -470,80 +470,36 @@ func volCreate(d *schema.ResourceData, meta interface{}, volName, profile, zone if err != nil { return err } - options := &vpcv1.CreateVolumeOptions{ - VolumePrototype: &vpcv1.VolumePrototype{ - Name: &volName, - Zone: &vpcv1.ZoneIdentity{ - Name: &zone, - }, - Profile: &vpcv1.VolumeProfileIdentity{ - Name: &profile, - }, + options := &vpcv1.CreateVolumeOptions{} + volTemplate := &vpcv1.VolumePrototype{ + Name: &volName, + Zone: &vpcv1.ZoneIdentity{ + Name: &zone, + }, + Profile: &vpcv1.VolumeProfileIdentity{ + Name: &profile, }, } - volTemplate := options.VolumePrototype.(*vpcv1.VolumePrototype) - var volCapacity int64 if sourceSnapsht, ok := d.GetOk(isVolumeSourceSnapshot); ok { sourceSnapshot := sourceSnapsht.(string) snapshotIdentity := &vpcv1.SnapshotIdentity{ ID: &sourceSnapshot, } volTemplate.SourceSnapshot = snapshotIdentity - getSnapshotOptions := &vpcv1.GetSnapshotOptions{ - ID: &sourceSnapshot, - } - snapshot, response, err := sess.GetSnapshot(getSnapshotOptions) - if err != nil { - return fmt.Errorf("[ERROR] Error fetching snapshot %s\n%s", err, response) - } - if (response != nil && response.StatusCode == 404) || snapshot == nil { - return fmt.Errorf("[ERROR] No snapshot found with id %s", sourceSnapshot) - } - minimumCapacity := *snapshot.MinimumCapacity - if capacity, ok := d.GetOk(isVolumeCapacity); ok { - if int64(capacity.(int)) > minimumCapacity { - volCapacity = int64(capacity.(int)) - } else { - volCapacity = minimumCapacity - } - volTemplate.Capacity = &volCapacity - } - } else if sourceSnapshtCrn, ok := d.GetOk(isVolumeSourceSnapshot); ok { + } else if sourceSnapshtCrn, ok := d.GetOk(isVolumeSourceSnapshotCrn); ok { sourceSnapshot := sourceSnapshtCrn.(string) snapshotIdentity := &vpcv1.SnapshotIdentity{ CRN: &sourceSnapshot, } volTemplate.SourceSnapshot = snapshotIdentity - getSnapshotOptions := &vpcv1.GetSnapshotOptions{ - ID: &sourceSnapshot, - } - snapshot, response, err := sess.GetSnapshot(getSnapshotOptions) - if err != nil { - return fmt.Errorf("[ERROR] Error fetching snapshot %s\n%s", err, response) - } - if (response != nil && response.StatusCode == 404) || snapshot == nil { - return fmt.Errorf("[ERROR] No snapshot found with id %s", sourceSnapshot) - } - minimumCapacity := *snapshot.MinimumCapacity - if capacity, ok := d.GetOk(isVolumeCapacity); ok { - if int64(capacity.(int)) > minimumCapacity { - volCapacity = int64(capacity.(int)) - } else { - volCapacity = minimumCapacity - } + } + if capacity, ok := d.GetOk(isVolumeCapacity); ok { + if int64(capacity.(int)) > 0 { + volCapacity := int64(capacity.(int)) volTemplate.Capacity = &volCapacity } - } else { - if capacity, ok := d.GetOk(isVolumeCapacity); ok { - if int64(capacity.(int)) > 0 { - volCapacity = int64(capacity.(int)) - } - } else { - volCapacity = 100 - } - volTemplate.Capacity = &volCapacity } if key, ok := d.GetOk(isVolumeEncryptionKey); ok { @@ -583,7 +539,7 @@ func volCreate(d *schema.ResourceData, meta interface{}, volName, profile, zone volTemplate.UserTags = userTagsArray } } - + options.VolumePrototype = volTemplate vol, response, err := sess.CreateVolume(options) if err != nil { return fmt.Errorf("[DEBUG] Create volume err %s\n%s", err, response) diff --git a/metadata/provider_metadata.json b/metadata/provider_metadata.json index 60f5eb3285..63805d34fb 100644 --- a/metadata/provider_metadata.json +++ b/metadata/provider_metadata.json @@ -107426,6 +107426,13 @@ "description": "Allow outbound connections to public destinations", "default_value": false, "optional": true + }, + { + "name": "enable_secure_by_default", + "type": "TypeBool", + "description": "Enable Secure-by-default security group configuration on existing cluster", + "default_value": false, + "optional": true } ], "ibm_container_vpc_worker": [ diff --git a/version/version.go b/version/version.go index 3f21f90597..58356ac3be 100644 --- a/version/version.go +++ b/version/version.go @@ -5,7 +5,7 @@ import ( ) // Version is the current provider main version -const Version = "1.71.1" +const Version = "1.72.0-beta0" // GitCommit is the git commit that was compiled. This will be filled in by the compiler. var GitCommit string diff --git a/website/allowed-subcategories.txt b/website/allowed-subcategories.txt index 74a627221c..2d74306a9b 100644 --- a/website/allowed-subcategories.txt +++ b/website/allowed-subcategories.txt @@ -12,6 +12,7 @@ Container Registry Configuration Aggregator Context Based Restrictions CD Tekton Pipeline +Db2 SaaS Direct Link Gateway DNS Services Enterprise Management @@ -28,7 +29,7 @@ Key Management Service Kubernetes Service Logs Routing Metrics Router -MQ on Cloud +MQaaS Object Storage Partner Center Sell Power Systems diff --git a/website/docs/d/code_engine_app.html.markdown b/website/docs/d/code_engine_app.html.markdown index 9cc6639eb8..48a5fe711b 100644 --- a/website/docs/d/code_engine_app.html.markdown +++ b/website/docs/d/code_engine_app.html.markdown @@ -148,7 +148,7 @@ Nested schema for **run_volume_mounts**: * Constraints: The default value is `100`. * `scale_concurrency_target` - (Integer) Optional threshold of concurrent requests per instance at which one or more additional instances are created. Use this value to scale up instances based on concurrent number of requests. This option defaults to the value of the `scale_concurrency` option, if not specified. - + * Constraints: The default value is `100`. The maximum value is `1000`. The minimum value is `1`. * `scale_cpu_limit` - (String) Optional number of CPU set for the instance of the app. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). * Constraints: The default value is `1`. The maximum length is `10` characters. The minimum length is `0` characters. The value must match regular expression `/^([0-9.]+)([eEinumkKMGTPB]*)$/`. diff --git a/website/docs/d/db2_instance.html.markdown b/website/docs/d/db2_instance.html.markdown new file mode 100644 index 0000000000..9d668dba85 --- /dev/null +++ b/website/docs/d/db2_instance.html.markdown @@ -0,0 +1,50 @@ +--- +subcategory: "Db2 SaaS" +layout: "ibm" +page_title: "IBM : ibm_db2" +description: |- + Get Information about IBM Db2 SaaS instance. +--- + +# ibm_db2 + +Retrieve information about an existing [IBM Db2 SaaS Instance](https://cloud.ibm.com/docs/Db2onCloud). + +**Note** +Configuration of an IBM Db2 SaaS on IBM Cloud Instance `data_source` requires that the `region` parameter is set for the IBM provider in the `provider.tf`. The region must be the same as the `location` that the IBM Cloud Databases instance is deployed into.A `terraform refresh` of the `data_source` fails if the region and the location differ. + +## Example usage +The following example retrieves information about the `db2_instance` instance in `us-south`. + +```terraform +data "ibm_db2" "db2_instance" { + name = "" + resource_group_id = data.ibm_resource_group.group.id + location = "us-south" + service = "dashdb-for-transactions" +} +``` + +## Argument reference +Review the argument reference that you can specify for your data source. + +- `name` - (Required, String) The name of the IBM Db2 SaaS on IBM Cloud instance. IBM Cloud does not enforce that service names are unique and it is possible that duplicate service names exist. The first located service instance is used by Terraform. The name must not include spaces. +- `location` - (Optional, String) The location where the IBM Db2 SaaS on IBM Cloud instance is deployed into. +- `resource_group_id`- (Optional, String) The ID of the resource group where the IBM Db2 SaaS on IBM Cloud instance is deployed into. The default is `default`. +- `service` - (Optional, String) The service type of the instance. To retrieve this value, run `ibmcloud catalog service-marketplace` or `ibmcloud catalog search`. + +## Attribute reference +In addition to all argument references list, you can access the following attribute references after your data source is created. + +- `guid` - (String) The unique identifier of the IBM Db2 SaaS on IBM Cloud instance. +- `resource_crn` - (String) The unique identifier(CRN) of the IBM Db2 SaaS on IBM Cloud instance. +- `plan` - (String) The service plan of the IBM Db2 SaaS on IBM Cloud instance. +- `location` - (String) The location where the IBM Db2 SaaS on IBM Cloud instance is deployed into. +- `status` - (String) The status of the IBM Db2 SaaS on IBM Cloud instance. +- `version` - (String) The database version. +- `platform_options`- (String) The CRN of key protect key. + + Nested scheme for `platform_options`: + - `disk_encryption_key_crn`- (String) The CRN of disk encryption key. + - `backup_encryption_key_crn`- (String) The CRN of backup encryption key. + diff --git a/website/docs/d/iam_effective_account_settings.html.markdown b/website/docs/d/iam_effective_account_settings.html.markdown new file mode 100644 index 0000000000..03c39018f4 --- /dev/null +++ b/website/docs/d/iam_effective_account_settings.html.markdown @@ -0,0 +1,142 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_iam_effective_account_settings" +description: |- + Get information about iam_effective_account_settings +subcategory: "IAM Identity Services" +--- + +# ibm_iam_effective_account_settings + +Provides a read-only data source to retrieve information about iam_effective_account_settings. 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_iam_effective_account_settings" "iam_effective_account_settings" { + account_id = "account_id" +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +* `account_id` - (Required, Forces new resource, String) Unique ID of the account. +* `include_history` - (Optional, Boolean) Defines if the entity history is included in the response. + * Constraints: The default value is `false`. +* `resolve_user_mfa` - (Optional, Boolean) Enrich MFA exemptions with user information. + * Constraints: The default value is `false`. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +* `id` - The unique identifier of the iam_effective_account_settings. +* `account` - (List) +Nested schema for **account**: + * `account_id` - (String) Unique ID of the account. + * `allowed_ip_addresses` - (String) Defines the IP addresses and subnets from which IAM tokens can be created for the account. + * `history` - (List) History of the Account Settings. + Nested schema for **history**: + * `action` - (String) Action of the history entry. + * `iam_id` - (String) IAM ID of the identity which triggered the action. + * `iam_id_account` - (String) Account of the identity which triggered the action. + * `message` - (String) Message which summarizes the executed action. + * `params` - (List) Params of the history entry. + * `timestamp` - (String) Timestamp when the action was triggered. + * `max_sessions_per_identity` - (String) Defines the max allowed sessions per identity required by the account. Valid values: * Any whole number greater than 0 * NOT_SET - To unset account setting and use service default. + * `mfa` - (String) Defines the MFA requirement for the user. Valid values: * NONE - No MFA trait set * NONE_NO_ROPC- No MFA, disable CLI logins with only a password * TOTP - For all non-federated IBMId users * TOTP4ALL - For all users * LEVEL1 - Email-based MFA for all users * LEVEL2 - TOTP-based MFA for all users * LEVEL3 - U2F MFA for all users. + * Constraints: Allowable values are: `NONE`, `NONE_NO_ROPC`, `TOTP`, `TOTP4ALL`, `LEVEL1`, `LEVEL2`, `LEVEL3`. + * `restrict_create_platform_apikey` - (String) Defines whether or not creating platform API keys is access controlled. Valid values: * RESTRICTED - to apply access control * NOT_RESTRICTED - to remove access control * NOT_SET - to 'unset' a previous set value. + * Constraints: The default value is `NOT_SET`. Allowable values are: `RESTRICTED`, `NOT_RESTRICTED`, `NOT_SET`. + * `restrict_create_service_id` - (String) Defines whether or not creating a service ID is access controlled. Valid values: * RESTRICTED - only users assigned the 'Service ID creator' role on the IAM Identity Service can create service IDs, including the account owner * NOT_RESTRICTED - all members of an account can create service IDs * NOT_SET - to 'unset' a previous set value. + * Constraints: The default value is `NOT_SET`. Allowable values are: `RESTRICTED`, `NOT_RESTRICTED`, `NOT_SET`. + * `session_expiration_in_seconds` - (String) Defines the session expiration in seconds for the account. Valid values: * Any whole number between between '900' and '86400' * NOT_SET - To unset account setting and use service default. + * Constraints: The default value is `86400`. + * `session_invalidation_in_seconds` - (String) Defines the period of time in seconds in which a session will be invalidated due to inactivity. Valid values: * Any whole number between '900' and '7200' * NOT_SET - To unset account setting and use service default. + * Constraints: The default value is `7200`. + * `system_access_token_expiration_in_seconds` - (String) Defines the access token expiration in seconds. Valid values: * Any whole number between '900' and '3600' * NOT_SET - To unset account setting and use service default. + * Constraints: The default value is `3600`. + * `system_refresh_token_expiration_in_seconds` - (String) Defines the refresh token expiration in seconds. Valid values: * Any whole number between '900' and '259200' * NOT_SET - To unset account setting and use service default. + * Constraints: The default value is `259200`. + * `user_mfa` - (List) List of users that are exempted from the MFA requirement of the account. + Nested schema for **user_mfa**: + * `description` - (String) optional description. + * `email` - (String) email of the user. + * `iam_id` - (String) The iam_id of the user. + * `mfa` - (String) Defines the MFA requirement for the user. Valid values: * NONE - No MFA trait set * NONE_NO_ROPC- No MFA, disable CLI logins with only a password * TOTP - For all non-federated IBMId users * TOTP4ALL - For all users * LEVEL1 - Email-based MFA for all users * LEVEL2 - TOTP-based MFA for all users * LEVEL3 - U2F MFA for all users. + * Constraints: Allowable values are: `NONE`, `NONE_NO_ROPC`, `TOTP`, `TOTP4ALL`, `LEVEL1`, `LEVEL2`, `LEVEL3`. + * `name` - (String) name of the user account. + * `user_name` - (String) userName of the user. +* `assigned_templates` - (List) assigned template section. +Nested schema for **assigned_templates**: + * `allowed_ip_addresses` - (String) Defines the IP addresses and subnets from which IAM tokens can be created for the account. + * `max_sessions_per_identity` - (String) Defines the max allowed sessions per identity required by the account. Valid values: * Any whole number greater than 0 * NOT_SET - To unset account setting and use service default. + * `mfa` - (String) Defines the MFA requirement for the user. Valid values: * NONE - No MFA trait set * NONE_NO_ROPC- No MFA, disable CLI logins with only a password * TOTP - For all non-federated IBMId users * TOTP4ALL - For all users * LEVEL1 - Email-based MFA for all users * LEVEL2 - TOTP-based MFA for all users * LEVEL3 - U2F MFA for all users. + * Constraints: Allowable values are: `NONE`, `NONE_NO_ROPC`, `TOTP`, `TOTP4ALL`, `LEVEL1`, `LEVEL2`, `LEVEL3`. + * `restrict_create_platform_apikey` - (String) Defines whether or not creating platform API keys is access controlled. Valid values: * RESTRICTED - to apply access control * NOT_RESTRICTED - to remove access control * NOT_SET - to 'unset' a previous set value. + * Constraints: The default value is `NOT_SET`. Allowable values are: `RESTRICTED`, `NOT_RESTRICTED`, `NOT_SET`. + * `restrict_create_service_id` - (String) Defines whether or not creating a service ID is access controlled. Valid values: * RESTRICTED - only users assigned the 'Service ID creator' role on the IAM Identity Service can create service IDs, including the account owner * NOT_RESTRICTED - all members of an account can create service IDs * NOT_SET - to 'unset' a previous set value. + * Constraints: The default value is `NOT_SET`. Allowable values are: `RESTRICTED`, `NOT_RESTRICTED`, `NOT_SET`. + * `session_expiration_in_seconds` - (String) Defines the session expiration in seconds for the account. Valid values: * Any whole number between between '900' and '86400' * NOT_SET - To unset account setting and use service default. + * Constraints: The default value is `86400`. + * `session_invalidation_in_seconds` - (String) Defines the period of time in seconds in which a session will be invalidated due to inactivity. Valid values: * Any whole number between '900' and '7200' * NOT_SET - To unset account setting and use service default. + * Constraints: The default value is `7200`. + * `system_access_token_expiration_in_seconds` - (String) Defines the access token expiration in seconds. Valid values: * Any whole number between '900' and '3600' * NOT_SET - To unset account setting and use service default. + * Constraints: The default value is `3600`. + * `system_refresh_token_expiration_in_seconds` - (String) Defines the refresh token expiration in seconds. Valid values: * Any whole number between '900' and '259200' * NOT_SET - To unset account setting and use service default. + * Constraints: The default value is `259200`. + * `template_id` - (String) Template Id. + * `template_name` - (String) Template name. + * `template_version` - (Integer) Template version. + * `user_mfa` - (List) List of users that are exempted from the MFA requirement of the account. + Nested schema for **user_mfa**: + * `description` - (String) optional description. + * `email` - (String) email of the user. + * `iam_id` - (String) The iam_id of the user. + * `mfa` - (String) Defines the MFA requirement for the user. Valid values: * NONE - No MFA trait set * NONE_NO_ROPC- No MFA, disable CLI logins with only a password * TOTP - For all non-federated IBMId users * TOTP4ALL - For all users * LEVEL1 - Email-based MFA for all users * LEVEL2 - TOTP-based MFA for all users * LEVEL3 - U2F MFA for all users. + * Constraints: Allowable values are: `NONE`, `NONE_NO_ROPC`, `TOTP`, `TOTP4ALL`, `LEVEL1`, `LEVEL2`, `LEVEL3`. + * `name` - (String) name of the user account. + * `user_name` - (String) userName of the user. +* `context` - (List) Context with key properties for problem determination. +Nested schema for **context**: + * `cluster_name` - (String) The cluster name. + * `elapsed_time` - (String) The elapsed time in msec. + * `end_time` - (String) The finish time of the request. + * `host` - (String) The host of the server instance processing the request. + * `instance_id` - (String) The instance ID of the server instance processing the request. + * `operation` - (String) The operation of the inbound REST request. + * `start_time` - (String) The start time of the request. + * `thread_id` - (String) The thread ID of the server instance processing the request. + * `transaction_id` - (String) The transaction ID of the inbound REST request. + * `url` - (String) The URL of that cluster. + * `user_agent` - (String) The user agent of the inbound REST request. +* `effective` - (List) +Nested schema for **effective**: + * `allowed_ip_addresses` - (String) Defines the IP addresses and subnets from which IAM tokens can be created for the account. + * `max_sessions_per_identity` - (String) Defines the max allowed sessions per identity required by the account. Valid values: * Any whole number greater than 0 * NOT_SET - To unset account setting and use service default. + * `mfa` - (String) Defines the MFA requirement for the user. Valid values: * NONE - No MFA trait set * NONE_NO_ROPC- No MFA, disable CLI logins with only a password * TOTP - For all non-federated IBMId users * TOTP4ALL - For all users * LEVEL1 - Email-based MFA for all users * LEVEL2 - TOTP-based MFA for all users * LEVEL3 - U2F MFA for all users. + * Constraints: Allowable values are: `NONE`, `NONE_NO_ROPC`, `TOTP`, `TOTP4ALL`, `LEVEL1`, `LEVEL2`, `LEVEL3`. + * `restrict_create_platform_apikey` - (String) Defines whether or not creating platform API keys is access controlled. Valid values: * RESTRICTED - to apply access control * NOT_RESTRICTED - to remove access control * NOT_SET - to 'unset' a previous set value. + * Constraints: The default value is `NOT_SET`. Allowable values are: `RESTRICTED`, `NOT_RESTRICTED`, `NOT_SET`. + * `restrict_create_service_id` - (String) Defines whether or not creating a service ID is access controlled. Valid values: * RESTRICTED - only users assigned the 'Service ID creator' role on the IAM Identity Service can create service IDs, including the account owner * NOT_RESTRICTED - all members of an account can create service IDs * NOT_SET - to 'unset' a previous set value. + * Constraints: The default value is `NOT_SET`. Allowable values are: `RESTRICTED`, `NOT_RESTRICTED`, `NOT_SET`. + * `session_expiration_in_seconds` - (String) Defines the session expiration in seconds for the account. Valid values: * Any whole number between between '900' and '86400' * NOT_SET - To unset account setting and use service default. + * Constraints: The default value is `86400`. + * `session_invalidation_in_seconds` - (String) Defines the period of time in seconds in which a session will be invalidated due to inactivity. Valid values: * Any whole number between '900' and '7200' * NOT_SET - To unset account setting and use service default. + * Constraints: The default value is `7200`. + * `system_access_token_expiration_in_seconds` - (String) Defines the access token expiration in seconds. Valid values: * Any whole number between '900' and '3600' * NOT_SET - To unset account setting and use service default. + * Constraints: The default value is `3600`. + * `system_refresh_token_expiration_in_seconds` - (String) Defines the refresh token expiration in seconds. Valid values: * Any whole number between '900' and '259200' * NOT_SET - To unset account setting and use service default. + * Constraints: The default value is `259200`. + * `user_mfa` - (List) List of users that are exempted from the MFA requirement of the account. + Nested schema for **user_mfa**: + * `description` - (String) optional description. + * `email` - (String) email of the user. + * `iam_id` - (String) The iam_id of the user. + * `mfa` - (String) Defines the MFA requirement for the user. Valid values: * NONE - No MFA trait set * NONE_NO_ROPC- No MFA, disable CLI logins with only a password * TOTP - For all non-federated IBMId users * TOTP4ALL - For all users * LEVEL1 - Email-based MFA for all users * LEVEL2 - TOTP-based MFA for all users * LEVEL3 - U2F MFA for all users. + * Constraints: Allowable values are: `NONE`, `NONE_NO_ROPC`, `TOTP`, `TOTP4ALL`, `LEVEL1`, `LEVEL2`, `LEVEL3`. + * `name` - (String) name of the user account. + * `user_name` - (String) userName of the user. + diff --git a/website/docs/d/is_bare_metal_server.markdown b/website/docs/d/is_bare_metal_server.markdown index b0a118b2a0..1612f89eb0 100644 --- a/website/docs/d/is_bare_metal_server.markdown +++ b/website/docs/d/is_bare_metal_server.markdown @@ -6,7 +6,7 @@ description: |- Manages IBM Cloud Bare Metal Server. --- -# ibm\_is_bare_metal_server +# ibm_is_bare_metal_server Import the details of an existing IBM Cloud Bare Metal Server as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about bare metal servers, see [About Bare Metal Servers for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-about-bare-metal-servers). @@ -70,6 +70,13 @@ In addition to all argument reference list, you can access the following attribu - `resource_type` - (String) The resource type - `size` - (Integer) The size of the disk in GB (gigabytes) - `enable_secure_boot` - (Boolean) Indicates whether secure boot is enabled. If enabled, the image must support secure boot or the server will fail to boot. +- `health_reasons` - (List) The reasons for the current health_state (if any). + + Nested scheme for `health_reasons`: + - `code` - (String) A snake case string succinctly identifying the reason for this health state. + - `message` - (String) An explanation of the reason for this health state. + - `more_info` - (String) Link to documentation about the reason for this health state. +- `health_state` - (String) The health of this resource. - `href` - (String) The URL for this bare metal server - `id` - (String) The unique identifier for this bare metal server - `image` - (String) Image used in the bare metal server. @@ -95,8 +102,35 @@ In addition to all argument reference list, you can access the following attribu - `name` - (String) The name for this reserved IP. The name is unique across all reserved IPs in a subnet. - `resource_type` - (String) The resource type. + - `reservation`- (List) The reservation used by this bare metal server. + Nested scheme for `reservation`: + - `crn` - (String) The CRN for this reservation. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted, and provides some supplementary information. + + Nested `deleted` blocks have the following structure: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this reservation. + - `id` - (String) The unique identifier for this reservation. + - `name` - (string) The name for this reservation. The name is unique across all reservations in the region. + - `resource_type` - (string) The resource type. + - `reservation_affinity`- (List) The bare metal server reservation affinity. + + Nested scheme for `reservation_affinity`: + - `policy` - (String) The reservation affinity policy to use for this bare metal server. + - `pool` - (List) The pool of reservations available for use by this bare metal server. + + Nested `pool` blocks have the following structure: + - `crn` - (String) The CRN for this reservation. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted, and provides some supplementary information. + + Nested `deleted` blocks have the following structure: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this reservation. + - `id` - (String) The unique identifier for this reservation. + - `name` - (string) The name for this reservation. The name is unique across all reservations in the region. + - `resource_type` - (string) The resource type. - `resource_type` - (String) The resource type. - - `subnet` - (List) The subnet of the virtual network interface for the network attachment. + - `subnet` - (List) The subnet of the virtual network interface for the network attachment. Nested schema for **subnet**: - `crn` - (String) The CRN for this subnet. - `deleted` - (List) If present, this property indicates the referenced resource has been deleted, and providessome supplementary information. diff --git a/website/docs/d/is_bare_metal_server_network_interface_floating_ip.markdown b/website/docs/d/is_bare_metal_server_network_interface_floating_ip.markdown index 3ebf3f5077..a640d64ccc 100644 --- a/website/docs/d/is_bare_metal_server_network_interface_floating_ip.markdown +++ b/website/docs/d/is_bare_metal_server_network_interface_floating_ip.markdown @@ -24,7 +24,7 @@ provider "ibm" { ```terraform - data "is_bare_metal_server_network_interface_floating_ip" "test" { + data "ibm_is_bare_metal_server_network_interface_floating_ip" "test" { bare_metal_server = ibm_is_bare_metal_server.example.id floating_ip = ibm_is_floating_ip.example.id network_interface = ibm_is_bare_metal_server_network_interface.example.id diff --git a/website/docs/d/is_bare_metal_server_network_interface_floating_ips.markdown b/website/docs/d/is_bare_metal_server_network_interface_floating_ips.markdown index dfc69fe6d7..8c459150ac 100644 --- a/website/docs/d/is_bare_metal_server_network_interface_floating_ips.markdown +++ b/website/docs/d/is_bare_metal_server_network_interface_floating_ips.markdown @@ -24,7 +24,7 @@ provider "ibm" { ```terraform - data "is_bare_metal_server_network_interface_floating_ips" "test" { + data "ibm_is_bare_metal_server_network_interface_floating_ips" "test" { bare_metal_server = "xxxx-xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx" network_interface = "xxxx-xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx" } diff --git a/website/docs/d/is_bare_metal_servers.markdown b/website/docs/d/is_bare_metal_servers.markdown index 037c5fd49a..6b73c612b3 100644 --- a/website/docs/d/is_bare_metal_servers.markdown +++ b/website/docs/d/is_bare_metal_servers.markdown @@ -6,7 +6,7 @@ description: |- Manages IBM Cloud Bare Metal Servers. --- -# ibm\_is_bare_metal_servers +# ibm_is_bare_metal_servers Import the details of an existing IBM Cloud vBare Metal Server collection as a read-only data source. You can then reference the fields of the data source in other resources within the same configuration using interpolation syntax. For more information, about bare metal servers, see [About Bare Metal Servers for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-about-bare-metal-servers). @@ -62,6 +62,13 @@ Review the attribute references that you can access after you retrieve your data - `resource_type` - (String) The resource type - `size` - (Integer) The size of the disk in GB (gigabytes) - `enable_secure_boot` - (Boolean) Indicates whether secure boot is enabled. If enabled, the image must support secure boot or the server will fail to boot. + - `health_reasons` - (List) The reasons for the current health_state (if any). + + Nested scheme for `health_reasons`: + - `code` - (String) A snake case string succinctly identifying the reason for this health state. + - `message` - (String) An explanation of the reason for this health state. + - `more_info` - (String) Link to documentation about the reason for this health state. + - `health_state` - (String) The health of this resource. - `href` - (String) The URL for this bare metal server - `id` - (String) The unique identifier for this bare metal server - `image` - (String) Image used in the bare metal server. @@ -180,6 +187,33 @@ Review the attribute references that you can access after you retrieve your data - `security_groups` - (Array) List of security groups. - `subnet` - (String) ID of the subnet. - `profile` - (String) The name for this bare metal server profile + - `reservation`- (List) The reservation used by this bare metal server. + Nested scheme for `reservation`: + - `crn` - (String) The CRN for this reservation. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted, and provides some supplementary information. + + Nested `deleted` blocks have the following structure: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this reservation. + - `id` - (String) The unique identifier for this reservation. + - `name` - (string) The name for this reservation. The name is unique across all reservations in the region. + - `resource_type` - (string) The resource type. + - `reservation_affinity`- (List) The bare metal server reservation affinity. + + Nested scheme for `reservation_affinity`: + - `policy` - (String) The reservation affinity policy to use for this bare metal server. + - `pool` - (List) The pool of reservations available for use by this bare metal server. + + Nested `pool` blocks have the following structure: + - `crn` - (String) The CRN for this reservation. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted, and provides some supplementary information. + + Nested `deleted` blocks have the following structure: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this reservation. + - `id` - (String) The unique identifier for this reservation. + - `name` - (string) The name for this reservation. The name is unique across all reservations in the region. + - `resource_type` - (string) The resource type. - `resource_group` - (String) resource group id of the bare metal server. - `resource_type` - (String) The type of resource referenced - `firmware_update_type_available` - (String) The firmware update type available for the bare metal server. diff --git a/website/docs/d/is_cluster_network.html.markdown b/website/docs/d/is_cluster_network.html.markdown new file mode 100644 index 0000000000..99a5b0460d --- /dev/null +++ b/website/docs/d/is_cluster_network.html.markdown @@ -0,0 +1,74 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_cluster_network" +description: |- + Get information about ClusterNetwork +subcategory: "VPC infrastructure" +--- + +# ibm_is_cluster_network + +Provides a read-only data source to retrieve information about a ClusterNetwork. 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_is_cluster_network" "is_cluster_network_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `cluster_network_id` - (Required, Forces new resource, String) The cluster network identifier. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +- `id` - The unique identifier of the ClusterNetwork. +- `created_at` - (String) The date and time that the cluster network was created. +- `crn` - (String) The CRN for this cluster network. +- `href` - (String) The URL for this cluster network. +- `lifecycle_reasons` - (List) The reasons for the current `lifecycle_state` (if any). + + Nested schema for **lifecycle_reasons**: + - `code` - (String) A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + - `message` - (String) An explanation of the reason for this lifecycle state. + - `more_info` - (String) Link to documentation about the reason for this lifecycle state. +- `lifecycle_state` - (String) The lifecycle state of the cluster network. +- `name` - (String) The name for this cluster network. The name must not be used by another cluster network in the region. +- `profile` - (List) The profile for this cluster network. +Nested schema for **profile**: + - `href` - (String) The URL for this cluster network profile. + - `name` - (String) The globally unique name for this cluster network profile. + - `resource_type` - (String) The resource type. +- `resource_group` - (List) The resource group for this cluster network. +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. +- `subnet_prefixes` - (List) The IP address ranges available for subnets for this cluster network. + + Nested schema for **subnet_prefixes**: + - `allocation_policy` - (String) The allocation policy for this subnet prefix:- `auto`: Subnets created by total count in this cluster network can use this prefix. + - `cidr` - (String) The CIDR block for this prefix. +- `vpc` - (List) The VPC this cluster network resides in. + + Nested schema for **vpc**: + - `crn` - (String) The CRN for this VPC. + - `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 VPC. + - `id` - (String) The unique identifier for this VPC. + - `name` - (String) The name for this VPC. The name is unique across all VPCs in the region. + - `resource_type` - (String) The resource type. +- `zone` - (List) The zone this cluster network resides in. + Nested schema for **zone**: + - `href` - (String) The URL for this zone. + - `name` - (String) The globally unique name for this zone. + diff --git a/website/docs/d/is_cluster_network_interface.html.markdown b/website/docs/d/is_cluster_network_interface.html.markdown new file mode 100644 index 0000000000..b3e417cf5f --- /dev/null +++ b/website/docs/d/is_cluster_network_interface.html.markdown @@ -0,0 +1,86 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_cluster_network_interface" +description: |- + Get information about ClusterNetworkInterface +subcategory: "VPC infrastructure" +--- + +# ibm_is_cluster_network_interface + +Provides a read-only data source to retrieve information about a ClusterNetworkInterface. 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_is_cluster_network_interface" "is_cluster_network_interface_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + cluster_network_interface_id = ibm_is_cluster_network_interface.is_cluster_network_interface_instance.cluster_network_interface_id +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `cluster_network_id` - (Required, Forces new resource, String) The cluster network identifier. +- `cluster_network_interface_id` - (Required, Forces new resource, String) The cluster network interface identifier. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +- `id` - The unique identifier of the ClusterNetworkInterface. +- `allow_ip_spoofing` - (Boolean) Indicates whether source IP spoofing is allowed on this cluster network interface. If `false`, source IP spoofing is prevented on this cluster network interface. If `true`, source IP spoofing is allowed on this cluster network interface. +- `auto_delete` - (Boolean) Indicates whether this cluster network interface will be automatically deleted when `target` is deleted. +- `created_at` - (String) The date and time that the cluster network interface was created. +- `enable_infrastructure_nat` - (Boolean) If `true`:- The VPC infrastructure performs any needed NAT operations.- `floating_ips` must not have more than one floating IP.If `false`:- Packets are passed unchanged to/from the virtual network interface, allowing the workload to perform any needed NAT operations. +- `href` - (String) The URL for this cluster network interface. +- `lifecycle_reasons` - (List) The reasons for the current `lifecycle_state` (if any). + Nested schema for **lifecycle_reasons**: + - `code` - (String) A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + - `message` - (String) An explanation of the reason for this lifecycle state. + - `more_info` - (String) Link to documentation about the reason for this lifecycle state. +- `lifecycle_state` - (String) The lifecycle state of the cluster network interface. +- `mac_address` - (String) The MAC address of the cluster network interface. May be absent if`lifecycle_state` is `pending`. +- `name` - (String) The name for this cluster network interface. The name is unique across all interfaces in the cluster network. +- `primary_ip` - (List) The cluster network subnet reserved IP for this cluster network interface. + Nested schema for **primary_ip**: + - `address` - (String) The IP address.If the address is pending allocation, the value will be `0.0.0.0`.This property may [expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) to support IPv6 addresses in the future. + - `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 cluster network subnet reserved IP. + - `id` - (String) The unique identifier for this cluster network subnet reserved IP. + - `name` - (String) The name for this cluster network subnet reserved IP. The name is unique across all reserved IPs in a cluster network subnet. + - `resource_type` - (String) The resource type. +- `subnet` - (List) + Nested schema for **subnet**: + - `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 cluster network subnet. + - `id` - (String) The unique identifier for this cluster network subnet. + - `name` - (String) The name for this cluster network subnet. The name is unique across all cluster network subnets in the cluster network. + - `resource_type` - (String) The resource type. +- `target` - (List) The target of this cluster network interface.If absent, this cluster network interface is not attached to a target.The resources supported by this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + Nested schema for **target**: + - `href` - (String) The URL for this instance cluster network attachment. + - `id` - (String) The unique identifier for this instance cluster network attachment. + - `name` - (String) The name for this instance cluster network attachment. The name is unique across all network attachments for the instance. + - `resource_type` - (String) The resource type. +- `vpc` - (List) The VPC this cluster network interface resides in. + Nested schema for **vpc**: + - `crn` - (String) The CRN for this VPC. + - `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 VPC. + - `id` - (String) The unique identifier for this VPC. + - `name` - (String) The name for this VPC. The name is unique across all VPCs in the region. + - `resource_type` - (String) The resource type. +- `zone` - (List) The zone this cluster network interface resides in. + Nested schema for **zone**: + - `href` - (String) The URL for this zone. + - `name` - (String) The globally unique name for this zone. + diff --git a/website/docs/d/is_cluster_network_interfaces.html.markdown b/website/docs/d/is_cluster_network_interfaces.html.markdown new file mode 100644 index 0000000000..b8f8b6ffcf --- /dev/null +++ b/website/docs/d/is_cluster_network_interfaces.html.markdown @@ -0,0 +1,90 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_cluster_network_interfaces" +description: |- + Get information about ClusterNetworkInterfaceCollection +subcategory: "VPC infrastructure" +--- + +# ibm_is_cluster_network_interfaces + +Provides a read-only data source to retrieve information about a ClusterNetworkInterfaceCollection. 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_is_cluster_network_interfaces" "is_cluster_network_interfaces_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `cluster_network_id` - (Required, Forces new resource, String) The cluster network identifier. +- `name` - (Optional, String) Filters the collection to resources with a `name` property matching the exact specified name. +- `sort` - (Optional, String) Sorts the returned collection by the specified property name in ascending order. A `-` may be prepended to the name to sort in descending order. For example, the value `-created_at` sorts the collection by the `created_at` property in descending order, and the value `name` sorts it by the `name` property in ascending order. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +- `id` - The unique identifier of the ClusterNetworkInterfaceCollection. +- `interfaces` - (List) A page of cluster network interfaces. + Nested schema for **interfaces**: + - `allow_ip_spoofing` - (Boolean) Indicates whether source IP spoofing is allowed on this cluster network interface. If `false`, source IP spoofing is prevented on this cluster network interface. If `true`, source IP spoofing is allowed on this cluster network interface. + - `auto_delete` - (Boolean) Indicates whether this cluster network interface will be automatically deleted when `target` is deleted. + - `created_at` - (String) The date and time that the cluster network interface was created. + - `enable_infrastructure_nat` - (Boolean) If `true`:- The VPC infrastructure performs any needed NAT operations.- `floating_ips` must not have more than one floating IP.If `false`:- Packets are passed unchanged to/from the virtual network interface, allowing the workload to perform any needed NAT operations. + - `href` - (String) The URL for this cluster network interface. + - `id` - (String) The unique identifier for this cluster network interface. + - `lifecycle_reasons` - (List) The reasons for the current `lifecycle_state` (if any). + Nested schema for **lifecycle_reasons**: + - `code` - (String) A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + - `message` - (String) An explanation of the reason for this lifecycle state. + - `more_info` - (String) Link to documentation about the reason for this lifecycle state. + - `lifecycle_state` - (String) The lifecycle state of the cluster network interface. + - `mac_address` - (String) The MAC address of the cluster network interface. May be absent if`lifecycle_state` is `pending`. + - `name` - (String) The name for this cluster network interface. The name is unique across all interfaces in the cluster network. + - `primary_ip` - (List) The cluster network subnet reserved IP for this cluster network interface. + Nested schema for **primary_ip**: + - `address` - (String) The IP address.If the address is pending allocation, the value will be `0.0.0.0`.This property may [expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) to support IPv6 addresses in the future. + - `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 cluster network subnet reserved IP. + - `id` - (String) The unique identifier for this cluster network subnet reserved IP. + - `name` - (String) The name for this cluster network subnet reserved IP. The name is unique across all reserved IPs in a cluster network subnet. + - `resource_type` - (String) The resource type. + - `resource_type` - (String) The resource type. + - `subnet` - (List) + Nested schema for **subnet**: + - `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 cluster network subnet. + - `id` - (String) The unique identifier for this cluster network subnet. + - `name` - (String) The name for this cluster network subnet. The name is unique across all cluster network subnets in the cluster network. + - `resource_type` - (String) The resource type. + - `target` - (List) The target of this cluster network interface.If absent, this cluster network interface is not attached to a target.The resources supported by this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + Nested schema for **target**: + - `href` - (String) The URL for this instance cluster network attachment. + - `id` - (String) The unique identifier for this instance cluster network attachment. + - `name` - (String) The name for this instance cluster network attachment. The name is unique across all network attachments for the instance. + - `resource_type` - (String) The resource type. + - `vpc` - (List) The VPC this cluster network interface resides in. + Nested schema for **vpc**: + - `crn` - (String) The CRN for this VPC. + - `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 VPC. + - `id` - (String) The unique identifier for this VPC. + - `name` - (String) The name for this VPC. The name is unique across all VPCs in the region. + - `resource_type` - (String) The resource type. + - `zone` - (List) The zone this cluster network interface resides in. + Nested schema for **zone**: + - `href` - (String) The URL for this zone. + - `name` - (String) The globally unique name for this zone. + diff --git a/website/docs/d/is_cluster_network_profile.html.markdown b/website/docs/d/is_cluster_network_profile.html.markdown new file mode 100644 index 0000000000..0c38c33bf0 --- /dev/null +++ b/website/docs/d/is_cluster_network_profile.html.markdown @@ -0,0 +1,44 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_cluster_network_profile" +description: |- + Get information about ClusterNetworkProfile +subcategory: "VPC infrastructure" +--- + +# ibm_is_cluster_network_profile + +Provides a read-only data source to retrieve information about a ClusterNetworkProfile. 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_is_cluster_network_profile" "is_cluster_network_profile" { + name = "h100" +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `name` - (Required, Forces new resource, String) The cluster network profile name. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +- `id` - The unique identifier of the ClusterNetworkProfile.(same as `name`) +- `family` - (String) The product family this cluster network profile belongs to.The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. +- `href` - (String) The URL for this cluster network profile. +- `resource_type` - (String) The resource type. +- `supported_instance_profiles` - (List) The instance profiles that support this cluster network profile. + Nested schema for **supported_instance_profiles**: + - `href` - (String) The URL for this virtual server instance profile. + - `name` - (String) The globally unique name for this virtual server instance profile. + - `resource_type` - (String) The resource type. +- `zones` - (List) Zones in this region that support this cluster network profile. + Nested schema for **zones**: + - `href` - (String) The URL for this zone. + - `name` - (String) The globally unique name for this zone. + diff --git a/website/docs/d/is_cluster_network_profiles.html.markdown b/website/docs/d/is_cluster_network_profiles.html.markdown new file mode 100644 index 0000000000..4eefaeb19f --- /dev/null +++ b/website/docs/d/is_cluster_network_profiles.html.markdown @@ -0,0 +1,43 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_cluster_network_profiles" +description: |- + Get information about ClusterNetworkProfileCollection +subcategory: "VPC infrastructure" +--- + +# ibm_is_cluster_network_profiles + +Provides a read-only data source to retrieve information about a ClusterNetworkProfileCollection. 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_is_cluster_network_profiles" "is_cluster_network_profiles" { +} +``` + + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +- `id` - The unique identifier of the ClusterNetworkProfileCollection. +- `profiles` - (List) A page of cluster network profiles. + + Nested schema for **profiles**: + - `family` - (String) The product family this cluster network profile belongs to.The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + - `href` - (String) The URL for this cluster network profile. + - `name` - (String) The globally unique name for this cluster network profile. + - `resource_type` - (String) The resource type. + - `supported_instance_profiles` - (List) The instance profiles that support this cluster network profile. + Nested schema for **supported_instance_profiles**: + - `href` - (String) The URL for this virtual server instance profile. + - `name` - (String) The globally unique name for this virtual server instance profile. + - `resource_type` - (String) The resource type. + - `zones` - (List) Zones in this region that support this cluster network profile. + + Nested schema for **zones**: + - `href` - (String) The URL for this zone. + - `name` - (String) The globally unique name for this zone. + diff --git a/website/docs/d/is_cluster_network_subnet.html.markdown b/website/docs/d/is_cluster_network_subnet.html.markdown new file mode 100644 index 0000000000..ee5de289b0 --- /dev/null +++ b/website/docs/d/is_cluster_network_subnet.html.markdown @@ -0,0 +1,49 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_cluster_network_subnet" +description: |- + Get information about ClusterNetworkSubnet +subcategory: "VPC infrastructure" +--- + +# ibm_is_cluster_network_subnet + +Provides a read-only data source to retrieve information about a ClusterNetworkSubnet. 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_is_cluster_network_subnet" "is_cluster_network_subnet_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + cluster_network_subnet_id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `cluster_network_id` - (Required, Forces new resource, String) The cluster network identifier. +- `cluster_network_subnet_id` - (Required, Forces new resource, String) The cluster network subnet identifier. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +- `id` - The unique identifier of the ClusterNetworkSubnet. +- `available_ipv4_address_count` - (Integer) The number of IPv4 addresses in this cluster network subnet that are not in use, and have not been reserved by the user or the provider. +- `created_at` - (String) The date and time that the cluster network subnet was created. +- `href` - (String) The URL for this cluster network subnet. +- `ip_version` - (String) The IP version for this cluster network subnet.The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. +- `ipv4_cidr_block` - (String) The IPv4 range of this cluster network subnet, expressed in CIDR format. +- `lifecycle_reasons` - (List) The reasons for the current `lifecycle_state` (if any). + + Nested schema for **lifecycle_reasons**: + - `code` - (String) A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + - `message` - (String) An explanation of the reason for this lifecycle state. + - `more_info` - (String) Link to documentation about the reason for this lifecycle state. +- `lifecycle_state` - (String) The lifecycle state of the cluster network subnet. +- `name` - (String) The name for this cluster network subnet. The name is unique across all cluster network subnets in the cluster network. +- `resource_type` - (String) The resource type. +- `total_ipv4_address_count` - (Integer) The total number of IPv4 addresses in this cluster network subnet.Note: This is calculated as 2(32 - prefix length). For example, the prefix length `/24` gives:
2(32 - 24) = 28 = 256 addresses. + diff --git a/website/docs/d/is_cluster_network_subnet_reserved_ip.html.markdown b/website/docs/d/is_cluster_network_subnet_reserved_ip.html.markdown new file mode 100644 index 0000000000..56186b6b1f --- /dev/null +++ b/website/docs/d/is_cluster_network_subnet_reserved_ip.html.markdown @@ -0,0 +1,58 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_cluster_network_subnet_reserved_ip" +description: |- + Get information about ClusterNetworkSubnetReservedIP +subcategory: "VPC infrastructure" +--- + +# ibm_is_cluster_network_subnet_reserved_ip + +Provides a read-only data source to retrieve information about a ClusterNetworkSubnetReservedIP. 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_is_cluster_network_subnet_reserved_ip" "is_cluster_network_subnet_reserved_ip_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + cluster_network_subnet_id =ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + cluster_network_subnet_reserved_ip_id = ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip_instance.cluster_network_subnet_reserved_ip_id +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `cluster_network_id` - (Required, Forces new resource, String) The cluster network identifier. +- `cluster_network_subnet_id` - (Required, Forces new resource, String) The cluster network subnet identifier. +- `cluster_network_subnet_reserved_ip_id` - (Required, Forces new resource, String) The cluster network subnet reserved IP identifier. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +- `id` - The unique identifier of the ClusterNetworkSubnetReservedIP. +- `address` - (String) The IP address.If the address is pending allocation, the value will be `0.0.0.0`.This property may [expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) to support IPv6 addresses in the future. +- `auto_delete` - (Boolean) Indicates whether this cluster network subnet reserved IP member will be automatically deleted when either `target` is deleted, or the cluster network subnet reserved IP is unbound. +- `created_at` - (String) The date and time that the cluster network subnet reserved IP was created. +- `href` - (String) The URL for this cluster network subnet reserved IP. +- `lifecycle_reasons` - (List) The reasons for the current `lifecycle_state` (if any). + Nested schema for **lifecycle_reasons**: + - `code` - (String) A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + - `message` - (String) An explanation of the reason for this lifecycle state. + - `more_info` - (String) Link to documentation about the reason for this lifecycle state. +- `lifecycle_state` - (String) The lifecycle state of the cluster network subnet reserved IP. +- `name` - (String) The name for this cluster network subnet reserved IP. The name is unique across all reserved IPs in a cluster network subnet. +- `owner` - (String) The owner of the cluster network subnet reserved IPThe enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. +- `resource_type` - (String) The resource type. +- `target` - (List) The target this cluster network subnet reserved IP is bound to.If absent, this cluster network subnet reserved IP is provider-owned or unbound. + Nested schema for **target**: + - `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 cluster network interface. + - `id` - (String) The unique identifier for this cluster network interface. + - `name` - (String) The name for this cluster network interface. The name is unique across all interfaces in the cluster network. + - `resource_type` - (String) The resource type. + diff --git a/website/docs/d/is_cluster_network_subnet_reserved_ips.html.markdown b/website/docs/d/is_cluster_network_subnet_reserved_ips.html.markdown new file mode 100644 index 0000000000..b8726a99ce --- /dev/null +++ b/website/docs/d/is_cluster_network_subnet_reserved_ips.html.markdown @@ -0,0 +1,61 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_cluster_network_subnet_reserved_ips" +description: |- + Get information about ClusterNetworkSubnetReservedIPCollection +subcategory: "VPC infrastructure" +--- + +# ibm_is_cluster_network_subnet_reserved_ips + +Provides a read-only data source to retrieve information about a ClusterNetworkSubnetReservedIPCollection. 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_is_cluster_network_subnet_reserved_ips" "is_cluster_network_subnet_reserved_ips_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id + cluster_network_subnet_id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `cluster_network_id` - (Required, Forces new resource, String) The cluster network identifier. +- `cluster_network_subnet_id` - (Required, Forces new resource, String) The cluster network subnet identifier. +- `name` - (Optional, String) Filters the collection to resources with a `name` property matching the exact specified name. +- `sort` - (Optional, String) Sorts the returned collection by the specified property name in ascending order. A `-` may be prepended to the name to sort in descending order. For example, the value `-created_at` sorts the collection by the `created_at` property in descending order, and the value `name` sorts it by the `name` property in ascending order. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +- `id` - The unique identifier of the ClusterNetworkSubnetReservedIPCollection. +- `reserved_ips` - (List) A page of reserved IPs for the cluster network subnet. + Nested schema for **reserved_ips**: + - `address` - (String) The IP address.If the address is pending allocation, the value will be `0.0.0.0`.This property may [expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) to support IPv6 addresses in the future. + - `auto_delete` - (Boolean) Indicates whether this cluster network subnet reserved IP member will be automatically deleted when either `target` is deleted, or the cluster network subnet reserved IP is unbound. + - `created_at` - (String) The date and time that the cluster network subnet reserved IP was created. + - `href` - (String) The URL for this cluster network subnet reserved IP. + - `id` - (String) The unique identifier for this cluster network subnet reserved IP. + - `lifecycle_reasons` - (List) The reasons for the current `lifecycle_state` (if any). + Nested schema for **lifecycle_reasons**: + - `code` - (String) A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + - `message` - (String) An explanation of the reason for this lifecycle state. + - `more_info` - (String) Link to documentation about the reason for this lifecycle state. + - `lifecycle_state` - (String) The lifecycle state of the cluster network subnet reserved IP. + - `name` - (String) The name for this cluster network subnet reserved IP. The name is unique across all reserved IPs in a cluster network subnet. + - `owner` - (String) The owner of the cluster network subnet reserved IPThe enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + - `resource_type` - (String) The resource type. + - `target` - (List) The target this cluster network subnet reserved IP is bound to.If absent, this cluster network subnet reserved IP is provider-owned or unbound. + Nested schema for **target**: + - `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 cluster network interface. + - `id` - (String) The unique identifier for this cluster network interface. + - `name` - (String) The name for this cluster network interface. The name is unique across all interfaces in the cluster network. + - `resource_type` - (String) The resource type. + diff --git a/website/docs/d/is_cluster_network_subnets.html.markdown b/website/docs/d/is_cluster_network_subnets.html.markdown new file mode 100644 index 0000000000..78a5c442bc --- /dev/null +++ b/website/docs/d/is_cluster_network_subnets.html.markdown @@ -0,0 +1,52 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_cluster_network_subnets" +description: |- + Get information about ClusterNetworkSubnetCollection +subcategory: "VPC infrastructure" +--- + +# ibm_is_cluster_network_subnets + +Provides a read-only data source to retrieve information about a ClusterNetworkSubnetCollection. 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_is_cluster_network_subnets" "is_cluster_network_subnets_instance" { + cluster_network_id = ibm_is_cluster_network.is_cluster_network_instance.id +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `cluster_network_id` - (Required, Forces new resource, String) The cluster network identifier. +- `name` - (Optional, String) Filters the collection to resources with a `name` property matching the exact specified name. +- `sort` - (Optional, String) Sorts the returned collection by the specified property name in ascending order. A `-` may be prepended to the name to sort in descending order. For example, the value `-created_at` sorts the collection by the `created_at` property in descending order, and the value `name` sorts it by the `name` property in ascending order. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +- `id` - The unique identifier of the ClusterNetworkSubnetCollection. +- `subnets` - (List) A page of subnets for the cluster network. + + Nested schema for **subnets**: + - `available_ipv4_address_count` - (Integer) The number of IPv4 addresses in this cluster network subnet that are not in use, and have not been reserved by the user or the provider. + - `created_at` - (String) The date and time that the cluster network subnet was created. + - `href` - (String) The URL for this cluster network subnet. + - `id` - (String) The unique identifier for this cluster network subnet. + - `ip_version` - (String) The IP version for this cluster network subnet.The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + - `ipv4_cidr_block` - (String) The IPv4 range of this cluster network subnet, expressed in CIDR format. + - `lifecycle_reasons` - (List) The reasons for the current `lifecycle_state` (if any). + Nested schema for **lifecycle_reasons**: + - `code` - (String) A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + - `message` - (String) An explanation of the reason for this lifecycle state. + - `more_info` - (String) Link to documentation about the reason for this lifecycle state. + - `lifecycle_state` - (String) The lifecycle state of the cluster network subnet. + - `name` - (String) The name for this cluster network subnet. The name is unique across all cluster network subnets in the cluster network. + - `resource_type` - (String) The resource type. + - `total_ipv4_address_count` - (Integer) The total number of IPv4 addresses in this cluster network subnet.Note: This is calculated as 2(32 - prefix length). For example, the prefix length `/24` gives:
2(32 - 24) = 28 = 256 addresses. + diff --git a/website/docs/d/is_cluster_networks.html.markdown b/website/docs/d/is_cluster_networks.html.markdown new file mode 100644 index 0000000000..5200b1998e --- /dev/null +++ b/website/docs/d/is_cluster_networks.html.markdown @@ -0,0 +1,79 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_cluster_networks" +description: |- + Get information about ClusterNetworkCollection +subcategory: "VPC infrastructure" +--- + +# ibm_is_cluster_networks + +Provides a read-only data source to retrieve information about a ClusterNetworkCollection. 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_is_cluster_networks" "is_cluster_networks_instance" { +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `name` - (Optional, String) Filters the collection to resources with a `name` property matching the exact specified name. +- `resource_group_id` - (Optional, String) Filters the collection to resources with a `resource_group.id` property matching the specified identifier. +- `sort` - (Optional, String) Sorts the returned collection by the specified property name in ascending order. A `-` may be prepended to the name to sort in descending order. For example, the value `-created_at` sorts the collection by the `created_at` property in descending order, and the value `name` sorts it by the `name` property in ascending order. +- `vpc_crn` - (Optional, String) Filters the collection to cluster networks with a `vpc.crn` property matching the specified CRN. +- `vpc_id` - (Optional, String) Filters the collection to cluster networks with a `vpc.id` property matching the specified id. +- `vpc_name` - (Optional, String) Filters the collection to cluster networks with a `vpc.name` property matching the specified name. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +- `id` - The unique identifier of the ClusterNetworkCollection. +- `cluster_networks` - (List) A page of cluster networks. + + Nested schema for **cluster_networks**: + - `created_at` - (String) The date and time that the cluster network was created. + - `crn` - (String) The CRN for this cluster network. + - `href` - (String) The URL for this cluster network. + - `id` - (String) The unique identifier for this cluster network. + - `lifecycle_reasons` - (List) The reasons for the current `lifecycle_state` (if any). + Nested schema for **lifecycle_reasons**: + - `code` - (String) A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + - `message` - (String) An explanation of the reason for this lifecycle state. + - `more_info` - (String) Link to documentation about the reason for this lifecycle state. + - `lifecycle_state` - (String) The lifecycle state of the cluster network. + - `name` - (String) The name for this cluster network. The name must not be used by another cluster network in the region. + - `profile` - (List) The profile for this cluster network. + Nested schema for **profile**: + - `href` - (String) The URL for this cluster network profile. + - `name` - (String) The globally unique name for this cluster network profile. + - `resource_type` - (String) The resource type. + - `resource_group` - (List) The resource group for this cluster network. + 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. + - `subnet_prefixes` - (List) The IP address ranges available for subnets for this cluster network. + Nested schema for **subnet_prefixes**: + - `allocation_policy` - (String) The allocation policy for this subnet prefix:- `auto`: Subnets created by total count in this cluster network can use this prefix. + - `cidr` - (String) The CIDR block for this prefix. + - `vpc` - (List) The VPC this cluster network resides in. + Nested schema for **vpc**: + - `crn` - (String) The CRN for this VPC. + - `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 VPC. + - `id` - (String) The unique identifier for this VPC. + - `name` - (String) The name for this VPC. The name is unique across all VPCs in the region. + - `resource_type` - (String) The resource type. + - `zone` - (List) The zone this cluster network resides in. + Nested schema for **zone**: + - `href` - (String) The URL for this zone. + - `name` - (String) The globally unique name for this zone. + diff --git a/website/docs/d/is_instance.html.markdown b/website/docs/d/is_instance.html.markdown index 952a3cfe23..18b9c10a9b 100644 --- a/website/docs/d/is_instance.html.markdown +++ b/website/docs/d/is_instance.html.markdown @@ -127,7 +127,24 @@ In addition to all argument reference list, you can access the following attribu - `deleted` - (List) If present, this property indicates the referenced resource has been deleted, and provides some supplementary information. Nested schema for `deleted`: - `more_info` - (String) Link to documentation about deleted resources. - + +- `cluster_network` - (List) If present, the cluster network that this virtual server instance resides in. + Nested schema for **cluster_network**: + - `crn` - (String) The CRN for this cluster network. + - `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 cluster network. + - `id` - (String) The unique identifier for this cluster network. + - `name` - (String) The name for this cluster network. The name must not be used by another cluster network in the region. + - `resource_type` - (String) The resource type. +- `cluster_network_attachments` - (List) The cluster network attachments for this virtual server instance.The cluster network attachments are ordered for consistent instance configuration. + Nested schema for **cluster_network_attachments**: + - `href` - (String) The URL for this instance cluster network attachment. + - `id` - (String) The unique identifier for this instance cluster network attachment. + - `name` - (String) The name for this instance cluster network attachment. The name is unique across all network attachments for the instance. + - `resource_type` - (String) The resource type. + - `confidential_compute_mode` - (String) The confidential compute mode to use for this virtual server instance.If unspecified, the default confidential compute mode from the profile will be used. - `crn` - (String) The CRN of the instance. - `disks` - (List) Collection of the instance's disks. Nested `disks` blocks has the following structure: @@ -148,6 +165,13 @@ In addition to all argument reference list, you can access the following attribu - `manufacture` - (String) The manufacturer of the GPU. - `memory`- (Integer) The amount of memory that was allocated to the GPU. - `model` - (String) The model of the GPU. +- `health_reasons` - (List) The reasons for the current health_state (if any). + + Nested scheme for `health_reasons`: + - `code` - (String) A snake case string succinctly identifying the reason for this health state. + - `message` - (String) An explanation of the reason for this health state. + - `more_info` - (String) Link to documentation about the reason for this health state. +- `health_state` - (String) The health of this resource. - `id` - (String) The ID that was assigned to the Virtual Servers for VPC instance. - `image` - (String) The ID of the virtual server image that is used in the instance. - `keys`- (List) A list of SSH keys that were added to the instance during creation. diff --git a/website/docs/d/is_instance_cluster_network_attachment.html.markdown b/website/docs/d/is_instance_cluster_network_attachment.html.markdown new file mode 100644 index 0000000000..7fa28f4624 --- /dev/null +++ b/website/docs/d/is_instance_cluster_network_attachment.html.markdown @@ -0,0 +1,78 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_instance_cluster_network_attachment" +description: |- + Get information about InstanceClusterNetworkAttachment +subcategory: "VPC infrastructure" +--- + +# ibm_is_instance_cluster_network_attachment + +Provides a read-only data source to retrieve information about an InstanceClusterNetworkAttachment. 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_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment" { + instance_id = ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance.instance_id + instance_cluster_network_attachment_id = ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance.instance_cluster_network_attachment_id +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `instance_id` - (Required, Forces new resource, String) The virtual server instance identifier. +- `instance_cluster_network_attachment_id` - (Required, Forces new resource, String) The instance cluster network attachment identifier. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +- `id` - The unique identifier of the InstanceClusterNetworkAttachment. +- `before` - (List) The instance cluster network attachment that is immediately before. If absent, this is thelast instance cluster network attachment. + Nested schema for **before**: + - `href` - (String) The URL for this instance cluster network attachment. + - `id` - (String) The unique identifier for this instance cluster network attachment. + - `name` - (String) The name for this instance cluster network attachment. The name is unique across all network attachments for the instance. + - `resource_type` - (String) The resource type. +- `cluster_network_interface` - (List) The cluster network interface for this instance cluster network attachment. + Nested schema for **cluster_network_interface**: + - `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 cluster network interface. + - `id` - (String) The unique identifier for this cluster network interface. + - `name` - (String) The name for this cluster network interface. The name is unique across all interfaces in the cluster network. + - `primary_ip` - (List) The primary IP for this cluster network interface. + Nested schema for **primary_ip**: + - `address` - (String) The IP address.If the address is pending allocation, the value will be `0.0.0.0`.This property may [expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) to support IPv6 addresses in the future. + - `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 cluster network subnet reserved IP. + - `id` - (String) The unique identifier for this cluster network subnet reserved IP. + - `name` - (String) The name for this cluster network subnet reserved IP. The name is unique across all reserved IPs in a cluster network subnet. + - `resource_type` - (String) The resource type. + - `resource_type` - (String) The resource type. + - `subnet` - (List) + Nested schema for **subnet**: + - `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 cluster network subnet. + - `id` - (String) The unique identifier for this cluster network subnet. + - `name` - (String) The name for this cluster network subnet. The name is unique across all cluster network subnets in the cluster network. + - `resource_type` - (String) The resource type. +- `href` - (String) The URL for this instance cluster network attachment. +- `lifecycle_reasons` - (List) The reasons for the current `lifecycle_state` (if any). + Nested schema for **lifecycle_reasons**: + - `code` - (String) A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + - `message` - (String) An explanation of the reason for this lifecycle state. + - `more_info` - (String) Link to documentation about the reason for this lifecycle state. +- `lifecycle_state` - (String) The lifecycle state of the instance cluster network attachment. +- `name` - (String) The name for this instance cluster network attachment. The name is unique across all network attachments for the instance. +- `resource_type` - (String) The resource type. + diff --git a/website/docs/d/is_instance_cluster_network_attachments.html.markdown b/website/docs/d/is_instance_cluster_network_attachments.html.markdown new file mode 100644 index 0000000000..390221683a --- /dev/null +++ b/website/docs/d/is_instance_cluster_network_attachments.html.markdown @@ -0,0 +1,83 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_instance_cluster_network_attachments" +description: |- + Get information about InstanceClusterNetworkAttachmentCollection +subcategory: "VPC infrastructure" +--- + +# ibm_is_instance_cluster_network_attachments + +Provides a read-only data source to retrieve information about an InstanceClusterNetworkAttachmentCollection. 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_is_instance_cluster_network_attachments" "is_instance_cluster_network_attachments" { + instance_id = ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance.instance_id +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `instance_id` - (Required, Forces new resource, String) The virtual server instance identifier. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +- `id` - The unique identifier of the InstanceClusterNetworkAttachmentCollection. +- `cluster_network_attachments` - (List) A page of ordered cluster network attachments (sorted based on the `before` property) for the instance. A cluster network attachment represents a device to which a cluster network interface is attached. + Nested schema for **cluster_network_attachments**: + - `before` - (List) The instance cluster network attachment that is immediately before. If absent, this is thelast instance cluster network attachment. + + Nested schema for **before**: + - `href` - (String) The URL for this instance cluster network attachment. + - `id` - (String) The unique identifier for this instance cluster network attachment. + - `name` - (String) The name for this instance cluster network attachment. The name is unique across all network attachments for the instance. + - `resource_type` - (String) The resource type. + - `cluster_network_interface` - (List) The cluster network interface for this instance cluster network attachment. + Nested schema for **cluster_network_interface**: + - `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 cluster network interface. + - `id` - (String) The unique identifier for this cluster network interface. + - `name` - (String) The name for this cluster network interface. The name is unique across all interfaces in the cluster network. + - `primary_ip` - (List) The primary IP for this cluster network interface. + Nested schema for **primary_ip**: + - `address` - (String) The IP address.If the address is pending allocation, the value will be `0.0.0.0`.This property may [expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) to support IPv6 addresses in the future. + - `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 cluster network subnet reserved IP. + - `id` - (String) The unique identifier for this cluster network subnet reserved IP. + - `name` - (String) The name for this cluster network subnet reserved IP. The name is unique across all reserved IPs in a cluster network subnet. + - `resource_type` - (String) The resource type. + - `resource_type` - (String) The resource type. + - `subnet` - (List) + + Nested schema for **subnet**: + - `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 cluster network subnet. + - `id` - (String) The unique identifier for this cluster network subnet. + - `name` - (String) The name for this cluster network subnet. The name is unique across all cluster network subnets in the cluster network. + - `resource_type` - (String) The resource type. + - `href` - (String) The URL for this instance cluster network attachment. + - `id` - (String) The unique identifier for this instance cluster network attachment. + - `lifecycle_reasons` - (List) The reasons for the current `lifecycle_state` (if any). + + Nested schema for **lifecycle_reasons**: + - `code` - (String) A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + - `message` - (String) An explanation of the reason for this lifecycle state. + - `more_info` - (String) Link to documentation about the reason for this lifecycle state. + - `lifecycle_state` - (String) The lifecycle state of the instance cluster network attachment. + - `name` - (String) The name for this instance cluster network attachment. The name is unique across all network attachments for the instance. + - `resource_type` - (String) The resource type. + diff --git a/website/docs/d/is_instance_disk.html.markdown b/website/docs/d/is_instance_disk.html.markdown index 6128307a04..e0e0623212 100644 --- a/website/docs/d/is_instance_disk.html.markdown +++ b/website/docs/d/is_instance_disk.html.markdown @@ -73,7 +73,7 @@ data "ibm_is_instance" "example" { passphrase = "" } -data "is_instance_disk" "example" { +data "ibm_is_instance_disk" "example" { instance = data.ibm_is_instance.example.id disk = data.ibm_is_instance.example.disks.0.id } diff --git a/website/docs/d/is_instance_disks.html.markdown b/website/docs/d/is_instance_disks.html.markdown index e33036b748..70fb72a1a5 100644 --- a/website/docs/d/is_instance_disks.html.markdown +++ b/website/docs/d/is_instance_disks.html.markdown @@ -72,7 +72,7 @@ data "ibm_is_instance" "example" { passphrase = "" } -data "is_instance_disks" "example" { +data "ibm_is_instance_disks" "example" { instance = data.ibm_is_instance.example.id } ``` diff --git a/website/docs/d/is_instance_profile.html.markdown b/website/docs/d/is_instance_profile.html.markdown index 33240b04b0..7d9c593aba 100644 --- a/website/docs/d/is_instance_profile.html.markdown +++ b/website/docs/d/is_instance_profile.html.markdown @@ -53,6 +53,16 @@ In addition to the argument reference list, you can access the following attribu - `value` - (String) The value for this profile field. - `values` - (String) The permitted values for this profile field. +- `cluster_network_attachment_count` - (List) Nested `cluster_network_attachment_count` blocks have the following structure: + + Nested schema for **cluster_network_attachment_count**: + - `default` - (Integer) + - `max` - (Integer) The maximum value for this profile field. + - `min` - (Integer) The minimum value for this profile field. + - `step` - (Integer) + - `type` - (String) The type for this profile field. + - `values` - (List) The permitted values for this profile field. + - `confidential_compute_modes` - (List) Nested schema for **confidential_compute_modes**: @@ -167,6 +177,13 @@ In addition to the argument reference list, you can access the following attribu - `type` - (String) The type for this profile field. - `values` - (List) The supported `enable_secure_boot` values for an instance using this profile. +- `supported_cluster_network_profiles` - (List) The cluster network profiles that support this instance profile. + + Nested schema for **supported_cluster_network_profiles**: + - `href` - (String) The URL for this cluster network profile. + - `name` - (String) The globally unique name for this cluster network profile. + - `resource_type` - (String) The resource type. + - `vcpu_architecture` - (List) Nested `vcpu_architecture` blocks have the following structure: Nested scheme for `vcpu_architecture`: diff --git a/website/docs/d/is_instance_profiles.html.markdown b/website/docs/d/is_instance_profiles.html.markdown index f5519db608..5bbc7a3b17 100644 --- a/website/docs/d/is_instance_profiles.html.markdown +++ b/website/docs/d/is_instance_profiles.html.markdown @@ -50,6 +50,17 @@ You can access the following attribute references after your data source is crea - `type` - (String) The type for this profile field. - `value` - (String) The value for this profile field. - `values` - (String) The permitted values for this profile field. + + - `cluster_network_attachment_count` - (List) Nested `cluster_network_attachment_count` blocks have the following structure: + + Nested schema for **cluster_network_attachment_count**: + - `default` - (Integer) + - `max` - (Integer) The maximum value for this profile field. + - `min` - (Integer) The minimum value for this profile field. + - `step` - (Integer) + - `type` - (String) The type for this profile field. + - `values` - (List) The permitted values for this profile field. + - `confidential_compute_modes` - (List) Nested schema for **confidential_compute_modes**: @@ -160,13 +171,21 @@ You can access the following attribute references after your data source is crea Nested scheme for `port_speed`: - `type` - (String) The type for this profile field. - `value` - (String) The value for this profile field. - - `secure_boot_modes` - (List) + - `secure_boot_modes` - (List) Nested schema for **secure_boot_modes**: - `default` - (Boolean) The default secure boot mode for this profile. - `type` - (String) The type for this profile field. - `values` - (List) The supported `enable_secure_boot` values for an instance using this profile. - + + - `supported_cluster_network_profiles` - (List) The cluster network profiles that support this instance profile. + + Nested schema for **supported_cluster_network_profiles**: + - `href` - (String) The URL for this cluster network profile. + - `name` - (String) The globally unique name for this cluster network profile. + - `resource_type` - (String) The resource type. + + - `vcpu_architecture` - (List) Nested `vcpu_architecture` blocks have the following structure: Nested scheme for `vcpu_architecture`: diff --git a/website/docs/d/is_instance_template.html.markdown b/website/docs/d/is_instance_template.html.markdown index ac4b54dfec..3e3ca26037 100644 --- a/website/docs/d/is_instance_template.html.markdown +++ b/website/docs/d/is_instance_template.html.markdown @@ -57,6 +57,27 @@ You can access the following attribute references after your data source is crea - `profile` - (String) The profile for the boot volume configuration. - `size` - (String) The boot volume size to configure in giga bytes. - `tags` - (String) User Tags associated with the boot_volume. (https://cloud.ibm.com/apidocs/tagging#types-of-tags) +- `cluster_network_attachments` - (List) The cluster network attachments to create for this virtual server instance. A cluster network attachment represents a device that is connected to a cluster network. The number of network attachments must match one of the values from the instance profile's `cluster_network_attachment_count` before the instance can be started. + Nested schema for **cluster_network_attachments**: + - `cluster_network_interface` - (List) A cluster network interface for the instance cluster network attachment. This can bespecified using an existing cluster network interface that does not already have a `target`,or a prototype object for a new cluster network interface.This instance must reside in the same VPC as the specified cluster network interface. Thecluster network interface must reside in the same cluster network as the`cluster_network_interface` of any other `cluster_network_attachments` for this instance. + Nested schema for **cluster_network_interface**: + - `auto_delete` - (Boolean) Indicates whether this cluster network interface will be automatically deleted when `target` is deleted. + - `href` - (String) The URL for this cluster network interface. + - `id` - (String) The unique identifier for this cluster network interface. + - `name` - (String) The name for this cluster network interface. The name must not be used by another interface in the cluster network. Names beginning with `ibm-` are reserved for provider-owned resources, and are not allowed. If unspecified, the name will be a hyphenated list of randomly-selected words. + - `primary_ip` - (List) The primary IP address to bind to the cluster network interface. May be eithera cluster network subnet reserved IP identity, or a cluster network subnet reserved IPprototype object which will be used to create a new cluster network subnet reserved IP.If a cluster network subnet reserved IP identity is provided, the specified clusternetwork subnet reserved IP must be unbound.If a cluster network subnet reserved IP prototype object with an address is provided,the address must be available on the cluster network interface's cluster networksubnet. If no address is specified, an available address on the cluster network subnetwill be automatically selected and reserved. + Nested schema for **primary_ip**: + - `address` - (String) The IP address to reserve, which must not already be reserved on the subnet.If unspecified, an available address on the subnet will automatically be selected. + - `auto_delete` - (Boolean) Indicates whether this cluster network subnet reserved IP member will be automatically deleted when either `target` is deleted, or the cluster network subnet reserved IP is unbound. + - `href` - (String) The URL for this cluster network subnet reserved IP. + - `id` - (String) The unique identifier for this cluster network subnet reserved IP. + - `name` - (String) The name for this cluster network subnet reserved IP. The name must not be used by another reserved IP in the cluster network subnet. Names starting with `ibm-` are reserved for provider-owned resources, and are not allowed. If unspecified, the name will be a hyphenated list of randomly-selected words. + - `subnet` - (List) The associated cluster network subnet. Required if `primary_ip` does not specify acluster network subnet reserved IP identity. + Nested schema for **subnet**: + - `href` - (String) The URL for this cluster network subnet. + - `id` - (String) The unique identifier for this cluster network subnet. + - `name` - (String) The name for this cluster network attachment. Names must be unique within the instance the cluster network attachment resides in. If unspecified, the name will be a hyphenated list of randomly-selected words. Names starting with `ibm-` are reserved for provider-owned resources, and are not allowed. + - `confidential_compute_mode` - (String) The confidential compute mode to use for this virtual server instance.If unspecified, the default confidential compute mode from the profile will be used. - `catalog_offering` - (List) The [catalog](https://cloud.ibm.com/docs/account?topic=account-restrict-by-user&interface=ui) offering or offering version to use when provisioning this virtual server instance. If an offering is specified, the latest version of that offering will be used. The specified offering or offering version may be in a different account in the same [enterprise](https://cloud.ibm.com/docs/account?topic=account-what-is-enterprise), subject to IAM policies. diff --git a/website/docs/d/is_instance_templates.html.markdown b/website/docs/d/is_instance_templates.html.markdown index 9a746a15c7..4e99bad094 100644 --- a/website/docs/d/is_instance_templates.html.markdown +++ b/website/docs/d/is_instance_templates.html.markdown @@ -44,6 +44,28 @@ You can access the following attribute references after your data source is crea - `profile` - (String) The profile for the boot volume configuration. - `size` - (String) The boot volume size to configure in giga bytes. - `tags` - (String) User Tags associated with the volume. (https://cloud.ibm.com/apidocs/tagging#types-of-tags). + + - `cluster_network_attachments` - (List) The cluster network attachments to create for this virtual server instance. A cluster network attachment represents a device that is connected to a cluster network. The number of network attachments must match one of the values from the instance profile's `cluster_network_attachment_count` before the instance can be started. + Nested schema for **cluster_network_attachments**: + - `cluster_network_interface` - (List) A cluster network interface for the instance cluster network attachment. This can bespecified using an existing cluster network interface that does not already have a `target`,or a prototype object for a new cluster network interface.This instance must reside in the same VPC as the specified cluster network interface. Thecluster network interface must reside in the same cluster network as the`cluster_network_interface` of any other `cluster_network_attachments` for this instance. + Nested schema for **cluster_network_interface**: + - `auto_delete` - (Boolean) Indicates whether this cluster network interface will be automatically deleted when `target` is deleted. + - `href` - (String) The URL for this cluster network interface. + - `id` - (String) The unique identifier for this cluster network interface. + - `name` - (String) The name for this cluster network interface. The name must not be used by another interface in the cluster network. Names beginning with `ibm-` are reserved for provider-owned resources, and are not allowed. If unspecified, the name will be a hyphenated list of randomly-selected words. + - `primary_ip` - (List) The primary IP address to bind to the cluster network interface. May be eithera cluster network subnet reserved IP identity, or a cluster network subnet reserved IPprototype object which will be used to create a new cluster network subnet reserved IP.If a cluster network subnet reserved IP identity is provided, the specified clusternetwork subnet reserved IP must be unbound.If a cluster network subnet reserved IP prototype object with an address is provided,the address must be available on the cluster network interface's cluster networksubnet. If no address is specified, an available address on the cluster network subnetwill be automatically selected and reserved. + Nested schema for **primary_ip**: + - `address` - (String) The IP address to reserve, which must not already be reserved on the subnet.If unspecified, an available address on the subnet will automatically be selected. + - `auto_delete` - (Boolean) Indicates whether this cluster network subnet reserved IP member will be automatically deleted when either `target` is deleted, or the cluster network subnet reserved IP is unbound. + - `href` - (String) The URL for this cluster network subnet reserved IP. + - `id` - (String) The unique identifier for this cluster network subnet reserved IP. + - `name` - (String) The name for this cluster network subnet reserved IP. The name must not be used by another reserved IP in the cluster network subnet. Names starting with `ibm-` are reserved for provider-owned resources, and are not allowed. If unspecified, the name will be a hyphenated list of randomly-selected words. + - `subnet` - (List) The associated cluster network subnet. Required if `primary_ip` does not specify acluster network subnet reserved IP identity. + Nested schema for **subnet**: + - `href` - (String) The URL for this cluster network subnet. + - `id` - (String) The unique identifier for this cluster network subnet. + - `name` - (String) The name for this cluster network attachment. Names must be unique within the instance the cluster network attachment resides in. If unspecified, the name will be a hyphenated list of randomly-selected words. Names starting with `ibm-` are reserved for provider-owned resources, and are not allowed. + - `confidential_compute_mode` - (String) The confidential compute mode to use for this virtual server instance.If unspecified, the default confidential compute mode from the profile will be used. - `catalog_offering` - (List) The [catalog](https://cloud.ibm.com/docs/account?topic=account-restrict-by-user&interface=ui) offering or offering version to use when provisioning this virtual server instance. If an offering is specified, the latest version of that offering will be used. The specified offering or offering version may be in a different account in the same [enterprise](https://cloud.ibm.com/docs/account?topic=account-what-is-enterprise), subject to IAM policies. diff --git a/website/docs/d/is_instances.html.markdown b/website/docs/d/is_instances.html.markdown index effd99dcc0..32fd8110be 100644 --- a/website/docs/d/is_instances.html.markdown +++ b/website/docs/d/is_instances.html.markdown @@ -77,7 +77,26 @@ In addition to all argument reference list, you can access the following attribu - `deleted` - (List) If present, this property indicates the referenced resource has been deleted, and provides some supplementary information. Nested schema for `deleted`: - `more_info` - (String) Link to documentation about deleted resources. - + + - `cluster_network` - (List) If present, the cluster network that this virtual server instance resides in. + Nested schema for **cluster_network**: + - `crn` - (String) The CRN for this cluster network. + - `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 cluster network. + - `id` - (String) The unique identifier for this cluster network. + - `name` - (String) The name for this cluster network. The name must not be used by another cluster network in the region. + - `resource_type` - (String) The resource type. + - `cluster_network_attachments` - (List) The cluster network attachments for this virtual server instance.The cluster network attachments are ordered for consistent instance configuration. + + Nested schema for **cluster_network_attachments**: + - `href` - (String) The URL for this instance cluster network attachment. + - `id` - (String) The unique identifier for this instance cluster network attachment. + - `name` - (String) The name for this instance cluster network attachment. The name is unique across all network attachments for the instance. + - `resource_type` - (String) The resource type. + + - `confidential_compute_mode` - (String) The confidential compute mode to use for this virtual server instance.If unspecified, the default confidential compute mode from the profile will be used. - `crn` - (String) The CRN of the instance. - `disks` - (List) Collection of the instance's disks. Nested `disks` blocks has the following structure: @@ -97,6 +116,13 @@ In addition to all argument reference list, you can access the following attribu - `manufacture` - Manufacture of the gpu. - `memory` - Memory of the gpu. - `model` - Model of the gpu. + - `health_reasons` - (List) The reasons for the current health_state (if any). + + Nested scheme for `health_reasons`: + - `code` - (String) A snake case string succinctly identifying the reason for this health state. + - `message` - (String) An explanation of the reason for this health state. + - `more_info` - (String) Link to documentation about the reason for this health state. + - `health_state` - (String) The health of this resource. - `id` - (String) The ID that was assigned to the Virtual Servers for VPC instance. - `image` - (String) The ID of the virtual server image that is used in the instance. - `lifecycle_reasons`- (List) The reasons for the current lifecycle_state (if any). diff --git a/website/docs/d/is_placement_group.html.markdown b/website/docs/d/is_placement_group.html.markdown index 39c9b164b0..87e485c27b 100644 --- a/website/docs/d/is_placement_group.html.markdown +++ b/website/docs/d/is_placement_group.html.markdown @@ -23,7 +23,7 @@ provider "ibm" { ## Example usage ```terraform -data "is_placement_group" "example" { +data "ibm_is_placement_group" "example" { name = ibm_is_placement_group.example.name } ``` diff --git a/website/docs/d/is_placement_groups.html.markdown b/website/docs/d/is_placement_groups.html.markdown index c53561d56d..bd02dad3bf 100644 --- a/website/docs/d/is_placement_groups.html.markdown +++ b/website/docs/d/is_placement_groups.html.markdown @@ -24,7 +24,7 @@ provider "ibm" { ## Example usage ```terraform -data "is_placement_groups" "example" { +data "ibm_is_placement_groups" "example" { } ``` diff --git a/website/docs/d/mqcloud_application.html.markdown b/website/docs/d/mqcloud_application.html.markdown index 88c482dfd2..d9a96ae3be 100644 --- a/website/docs/d/mqcloud_application.html.markdown +++ b/website/docs/d/mqcloud_application.html.markdown @@ -3,14 +3,14 @@ layout: "ibm" page_title: "IBM : ibm_mqcloud_application" description: |- Get information about mqcloud_application -subcategory: "MQ on Cloud" +subcategory: "MQaaS" --- # 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. -> **Note:** The MQ on Cloud Terraform provider access is restricted to users of the reserved deployment plan. +> **Note:** The MQaaS Terraform provider access is restricted to users of the reserved deployment, reserved capacity, and reserved capacity subscription plans. ## Example Usage @@ -27,7 +27,7 @@ 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. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQaaS 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 diff --git a/website/docs/d/mqcloud_keystore_certificate.html.markdown b/website/docs/d/mqcloud_keystore_certificate.html.markdown index 889f379d25..0e201545e3 100644 --- a/website/docs/d/mqcloud_keystore_certificate.html.markdown +++ b/website/docs/d/mqcloud_keystore_certificate.html.markdown @@ -3,14 +3,14 @@ layout: "ibm" page_title: "IBM : ibm_mqcloud_keystore_certificate" description: |- Get information about mqcloud_keystore_certificate -subcategory: "MQ on Cloud" +subcategory: "MQaaS" --- # 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. -> **Note:** The MQ on Cloud Terraform provider access is restricted to users of the reserved deployment plan. +> **Note:** The MQaaS Terraform provider access is restricted to users of the reserved deployment, reserved capacity, and reserved capacity subscription plans. ## Example Usage @@ -30,7 +30,7 @@ You can specify the following arguments for this data source. * 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. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQaaS 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 diff --git a/website/docs/d/mqcloud_queue_manager.html.markdown b/website/docs/d/mqcloud_queue_manager.html.markdown index 8afd2affc7..3ec9dfb8fe 100644 --- a/website/docs/d/mqcloud_queue_manager.html.markdown +++ b/website/docs/d/mqcloud_queue_manager.html.markdown @@ -3,14 +3,14 @@ layout: "ibm" page_title: "IBM : ibm_mqcloud_queue_manager" description: |- Get information about mqcloud_queue_manager -subcategory: "MQ on Cloud" +subcategory: "MQaaS" --- # 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. -> **Note:** The MQ on Cloud Terraform provider access is restricted to users of the reserved deployment plan. +> **Note:** The MQaaS Terraform provider access is restricted to users of the reserved deployment, reserved capacity, and reserved capacity subscription plans. ## Example Usage @@ -27,7 +27,7 @@ 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. +* `service_instance_guid` - (Required, String) The GUID that uniquely identifies the MQaaS 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 diff --git a/website/docs/d/mqcloud_queue_manager_options.html.markdown b/website/docs/d/mqcloud_queue_manager_options.html.markdown index 2509f176fa..12b45bdfba 100644 --- a/website/docs/d/mqcloud_queue_manager_options.html.markdown +++ b/website/docs/d/mqcloud_queue_manager_options.html.markdown @@ -3,14 +3,14 @@ layout: "ibm" page_title: "IBM : ibm_mqcloud_queue_manager_options" description: |- Get information about mqcloud_queue_manager_options -subcategory: "MQ on Cloud" +subcategory: "MQaaS" --- # ibm_mqcloud_queue_manager_options Provides a read-only data source to retrieve information about mqcloud_queue_manager_options. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. -> **Note:** The MQ on Cloud Terraform provider access is restricted to users of the reserved deployment plan. +> **Note:** The MQaaS Terraform provider access is restricted to users of the reserved deployment, reserved capacity, and reserved capacity subscription plans. ## Example Usage @@ -24,7 +24,7 @@ data "ibm_mqcloud_queue_manager_options" "mqcloud_queue_manager_options" { You can specify the following arguments for this data source. -* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQ on Cloud service instance. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQaaS 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 diff --git a/website/docs/d/mqcloud_queue_manager_status.html.markdown b/website/docs/d/mqcloud_queue_manager_status.html.markdown index 9e82e488b7..4ca2533c4c 100644 --- a/website/docs/d/mqcloud_queue_manager_status.html.markdown +++ b/website/docs/d/mqcloud_queue_manager_status.html.markdown @@ -3,14 +3,14 @@ layout: "ibm" page_title: "IBM : ibm_mqcloud_queue_manager_status" description: |- Get information about mqcloud_queue_manager_status -subcategory: "MQ on Cloud" +subcategory: "MQaaS" --- # 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. -> **Note:** The MQ on Cloud Terraform provider access is restricted to users of the reserved deployment plan. +> **Note:** The MQaaS Terraform provider access is restricted to users of the reserved deployment, reserved capacity, and reserved capacity subscription plans. ## Example Usage @@ -27,7 +27,7 @@ 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. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQaaS 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 diff --git a/website/docs/d/mqcloud_truststore_certificate.html.markdown b/website/docs/d/mqcloud_truststore_certificate.html.markdown index abe3b6ac53..c46f1bb0f1 100644 --- a/website/docs/d/mqcloud_truststore_certificate.html.markdown +++ b/website/docs/d/mqcloud_truststore_certificate.html.markdown @@ -3,14 +3,14 @@ layout: "ibm" page_title: "IBM : ibm_mqcloud_truststore_certificate" description: |- Get information about mqcloud_truststore_certificate -subcategory: "MQ on Cloud" +subcategory: "MQaaS" --- # 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. -> **Note:** The MQ on Cloud Terraform provider access is restricted to users of the reserved deployment plan. +> **Note:** The MQaaS Terraform provider access is restricted to users of the reserved deployment, reserved capacity, and reserved capacity subscription plans. ## Example Usage @@ -30,7 +30,7 @@ You can specify the following arguments for this data source. * 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. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQaaS 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 diff --git a/website/docs/d/mqcloud_user.html.markdown b/website/docs/d/mqcloud_user.html.markdown index e451cd577e..bd861caec1 100644 --- a/website/docs/d/mqcloud_user.html.markdown +++ b/website/docs/d/mqcloud_user.html.markdown @@ -3,14 +3,14 @@ layout: "ibm" page_title: "IBM : ibm_mqcloud_user" description: |- Get information about mqcloud_user -subcategory: "MQ on Cloud" +subcategory: "MQaaS" --- # 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. -> **Note:** The MQ on Cloud Terraform provider access is restricted to users of the reserved deployment plan. +> **Note:** The MQaaS Terraform provider access is restricted to users of the reserved deployment, reserved capacity, and reserved capacity subscription plans. ## Example Usage @@ -27,7 +27,7 @@ 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. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQaaS 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 diff --git a/website/docs/d/mqcloud_virtual_private_endpoint_gateway.html.markdown b/website/docs/d/mqcloud_virtual_private_endpoint_gateway.html.markdown new file mode 100644 index 0000000000..5f6e73c879 --- /dev/null +++ b/website/docs/d/mqcloud_virtual_private_endpoint_gateway.html.markdown @@ -0,0 +1,49 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_mqcloud_virtual_private_endpoint_gateway" +description: |- + Get information about mqcloud_virtual_private_endpoint_gateway +subcategory: "MQaaS" +--- + +# ibm_mqcloud_virtual_private_endpoint_gateway + +Provides a read-only data source to retrieve information about a mqcloud_virtual_private_endpoint_gateway. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. + +> **Note:** The MQaaS Terraform provider access is restricted to users of the reserved deployment, reserved capacity, and reserved capacity subscription plans. + +## Example Usage + +```hcl +data "ibm_mqcloud_virtual_private_endpoint_gateway" "mqcloud_virtual_private_endpoint_gateway" { + service_instance_guid = ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance.service_instance_guid + trusted_profile = ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance.trusted_profile + virtual_private_endpoint_gateway_guid = ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance.virtual_private_endpoint_gateway_guid +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQaaS 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}$/`. +* `trusted_profile` - (Optional, String) The CRN of the trusted profile to assume for this request. + * Constraints: The maximum length is `512` characters. The minimum length is `9` characters. The value must match regular expression `/^crn:v[0-9]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]*:([a-z]\/[a-z0-9-]+)?:[a-z0-9-]*:[a-z0-9-]*:[a-zA-Z0-9-_\\.\/]*$|^crn:\\[\\.\\.\\.\\]$/`. +* `virtual_private_endpoint_gateway_guid` - (Required, Forces new resource, String) The id of the virtual private endpoint gateway. + * Constraints: The maximum length is `41` characters. The minimum length is `41` characters. The value must match regular expression `/^[0-9a-zA-Z]{4}-[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_virtual_private_endpoint_gateway. +* `href` - (String) URL for the details of the virtual private endpoint gateway. + * Constraints: The maximum length is `8000` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. +* `name` - (Forces new resource, String) The name of the virtual private endpoint gateway, created by the user. + * Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z]|[a-z][-a-z0-9]*[a-z0-9]$/`. +* `status` - (String) The lifecycle state of this virtual privage endpoint. + * Constraints: The maximum length is `12` characters. The minimum length is `2` characters. The value must match regular expression `/^deleting$|failed$|pending$|stable$|suspended$|updating$|waiting$/`. +* `target_crn` - (String) The CRN of the reserved capacity service instance the user is trying to connect to. + * Constraints: The maximum length is `512` characters. The minimum length is `9` characters. The value must match regular expression `/^crn:v[0-9]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]*:([a-z]\/[a-z0-9-]+)?:[a-z0-9-]*:[a-z0-9-]*:[a-zA-Z0-9-_\\.\/]*$|^crn:\\[\\.\\.\\.\\]$/`. + diff --git a/website/docs/d/mqcloud_virtual_private_endpoint_gateways.html.markdown b/website/docs/d/mqcloud_virtual_private_endpoint_gateways.html.markdown new file mode 100644 index 0000000000..f798cf640f --- /dev/null +++ b/website/docs/d/mqcloud_virtual_private_endpoint_gateways.html.markdown @@ -0,0 +1,54 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_mqcloud_virtual_private_endpoint_gateways" +description: |- + Get information about mqcloud_virtual_private_endpoint_gateways +subcategory: "MQaaS" +--- + +# ibm_mqcloud_virtual_private_endpoint_gateways + +Provides a read-only data source to retrieve information about mqcloud_virtual_private_endpoint_gateways. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. + +> **Note:** The MQaaS Terraform provider access is restricted to users of the reserved deployment, reserved capacity, and reserved capacity subscription plans. + +## Example Usage + +```hcl +data "ibm_mqcloud_virtual_private_endpoint_gateways" "mqcloud_virtual_private_endpoint_gateways" { + name = ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance.name + service_instance_guid = ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance.service_instance_guid + trusted_profile = ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway_instance.trusted_profile +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +* `name` - (Optional, Forces new resource, String) The name of the virtual private endpoint gateway, created by the user. + * Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z]|[a-z][-a-z0-9]*[a-z0-9]$/`. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQaaS 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}$/`. +* `trusted_profile` - (Optional, String) The CRN of the trusted profile to assume for this request. + * Constraints: The maximum length is `512` characters. The minimum length is `9` characters. The value must match regular expression `/^crn:v[0-9]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]*:([a-z]\/[a-z0-9-]+)?:[a-z0-9-]*:[a-z0-9-]*:[a-zA-Z0-9-_\\.\/]*$|^crn:\\[\\.\\.\\.\\]$/`. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +* `id` - The unique identifier of the mqcloud_virtual_private_endpoint_gateways. +* `virtual_private_endpoint_gateways` - (List) List of virtual private endpoint gateways. + * Constraints: The maximum length is `50` items. The minimum length is `0` items. +Nested schema for **virtual_private_endpoint_gateways**: + * `href` - (String) URL for the details of the virtual private endpoint gateway. + * Constraints: The maximum length is `8000` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + * `id` - (String) The ID of the virtual private endpoint gateway which was allocated on creation. + * Constraints: The maximum length is `41` characters. The minimum length is `41` characters. The value must match regular expression `/^[0-9a-zA-Z]{4}-[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}$/`. + * `name` - (Forces new resource, String) The name of the virtual private endpoint gateway, created by the user. + * Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z]|[a-z][-a-z0-9]*[a-z0-9]$/`. + * `status` - (String) The lifecycle state of this virtual privage endpoint. + * Constraints: The maximum length is `12` characters. The minimum length is `2` characters. The value must match regular expression `/^deleting$|failed$|pending$|stable$|suspended$|updating$|waiting$/`. + * `target_crn` - (String) The CRN of the reserved capacity service instance the user is trying to connect to. + * Constraints: The maximum length is `512` characters. The minimum length is `9` characters. The value must match regular expression `/^crn:v[0-9]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]*:([a-z]\/[a-z0-9-]+)?:[a-z0-9-]*:[a-z0-9-]*:[a-zA-Z0-9-_\\.\/]*$|^crn:\\[\\.\\.\\.\\]$/`. + diff --git a/website/docs/d/pi_datacenter.html.markdown b/website/docs/d/pi_datacenter.html.markdown index 1aefd065ec..6a0571c238 100644 --- a/website/docs/d/pi_datacenter.html.markdown +++ b/website/docs/d/pi_datacenter.html.markdown @@ -38,6 +38,7 @@ Example usage: Review the argument references that you can specify for your data source. +- `pi_cloud_instance_id` - (Optional, String) The GUID of the service instance associated with an account. Required if private datacenter. - `pi_datacenter_zone` - (Optional, String) Datacenter zone you want to retrieve. If no value is supplied, the `zone` configured within the IBM provider will be utilized. ## Attribute reference diff --git a/website/docs/d/pi_datacenters.html.markdown b/website/docs/d/pi_datacenters.html.markdown index cbaa14f0ee..2dfcfb91c6 100644 --- a/website/docs/d/pi_datacenters.html.markdown +++ b/website/docs/d/pi_datacenters.html.markdown @@ -30,6 +30,12 @@ Example usage: } ``` +## Argument reference + +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Optional, String) The GUID of the service instance associated with an account. Required if private datacenter. + ## Attribute reference In addition to all argument reference list, you can access the following attribute references after your data source is created. diff --git a/website/docs/d/pi_network.html.markdown b/website/docs/d/pi_network.html.markdown index befcce7a1c..c7951bb79d 100644 --- a/website/docs/d/pi_network.html.markdown +++ b/website/docs/d/pi_network.html.markdown @@ -7,9 +7,11 @@ 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 network install server](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-configuring-subnet). ## Example usage + ```terraform data "ibm_pi_network" "ds_network" { pi_network_name = "APP" @@ -17,13 +19,15 @@ data "ibm_pi_network" "ds_network" { } ``` -**Notes** +### Notes + - Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. - If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: - `region` - `lon` - `zone` - `lon04` Example usage: + ```terraform provider "ibm" { region = "lon" @@ -32,15 +36,17 @@ Example usage: ``` ## Argument reference -Review the argument references that you can specify for your data source. + +Review the argument references that you can specify for your data source. - `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. - `pi_network_name` - (Required, String) The name of the network. ## Attribute reference -In addition to all argument reference list, you can access the following attribute references after your data source is created. -- `access_config` - (String) The network communication configuration option of the network (for satellite locations only). +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `access_config` - (Deprecated, String) The network communication configuration option of the network (for on-prem locations only). Use `peer_id` instead. - `available_ip_count` - (Float) The total number of IP addresses that you have in your network. - `cidr` - (String) The CIDR of the network. - `crn` - (String) The CRN of this resource. @@ -49,6 +55,11 @@ In addition to all argument reference list, you can access the following attribu - `id` - (String) The ID of the network. - `jumbo` - (Deprecated, Boolean) MTU Jumbo option of the network (for multi-zone locations only). - `mtu` - (Boolean) Maximum Transmission Unit option of the network. +- `network_address_translation` - (List) Contains the network address translation details (for on-prem locations only). + + Nested schema for `network_address_translation`: + - `source_ip` - (String) source IP address. +- `peer_id` - (String) Network peer ID (for on-prem locations only). - `type` - (String) The type of network. - `used_ip_count` - (Float) The number of used IP addresses. - `used_ip_percent` - (Float) The percentage of IP addresses used. diff --git a/website/docs/d/pi_network_peers.html.markdown b/website/docs/d/pi_network_peers.html.markdown new file mode 100644 index 0000000000..f55811ca00 --- /dev/null +++ b/website/docs/d/pi_network_peers.html.markdown @@ -0,0 +1,54 @@ +--- +subcategory: "Power Systems" +layout: "ibm" +page_title: "IBM : ibm_pi_network_peers" +description: |- + Get information about IBM Power Virtual Server cloud network peers. +--- + +# ibm_pi_network_peers + +Provides a read-only data source to retrieve information about pi_network_peers for on-prem locations. + +## Example Usage + +```terraform +data "ibm_pi_network_peers" "pi_network_peers" { + pi_cloud_instance_id = "49fba6c9-23f8-40bc-9899-aca322ee7d5b" +} +``` + +### Notes + +- Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +- If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + - `region` - `lon` + - `zone` - `lon04` + +Example usage: + +```terraform + provider "ibm" { + region = "lon" + zone = "lon04" + } + ``` + +## Argument reference + +Review the argument references that you can specify for your data source. + +- `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. + +## Attribute Reference + +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `id` - (String) The unique identifier of the pi_network_peers. +- `network_peers` - (List) List of network peers. + + Nested schema for `network_peers`: + - `description` - (String) Description of the network peer. + - `id` - (String) ID of the network peer. + - `name` - (String) Name of the network peer. + - `type` - (String) Type of the network peer. diff --git a/website/docs/d/pi_networks.html.markdown b/website/docs/d/pi_networks.html.markdown index 2b030d6165..94f3a6e973 100644 --- a/website/docs/d/pi_networks.html.markdown +++ b/website/docs/d/pi_networks.html.markdown @@ -7,22 +7,26 @@ description: |- --- # ibm_pi_networks + Retrieve a list of networks that you can use in your Power Systems Virtual Server instance. For more information, about power virtual server instance networks, see [setting up an IBM network install server](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-configuring-subnet). ## Example usage + ```terraform data "ibm_pi_networks" "ds_network" { pi_cloud_instance_id = "49fba6c9-23f8-40bc-9899-aca322ee7d5b" } ``` -**Notes** +### Notes + - Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. - If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: - `region` - `lon` - `zone` - `lon04` Example usage: + ```terraform provider "ibm" { region = "lon" @@ -31,23 +35,26 @@ Example usage: ``` ## Argument reference -Review the argument references that you can specify for your data source. + +Review the argument references that you can specify for your data source. - `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. ## Attribute reference -In addition to all argument reference list, you can access the following attribute references after your data source is created. -- `networks` - (List) List of all networks. +In addition to all argument reference list, you can access the following attribute references after your data source is created. + +- `networks` - (List) List of all networks. Nested scheme for `networks`: - - `access_config` - (String) The network communication configuration option of the network (for satellite locations only). + - `access_config` - (Deprecated, String) The network communication configuration option of the network (for on-prem locations only). Use `peer_id` instead. - `crn` - (String) The CRN of this resource. - `dhcp_managed` - (Boolean) Indicates if the network DHCP Managed. - - `href` - (String) The hyper link of a network. + - `href` - (String) The hyper link of a network. - `mtu` - (Boolean) Maximum Transmission Unit option of the network. - `name` - (String) The name of a network. - `network_id` - (String) The ID of the network. + - `peer_id` - (String) Network peer ID (for on-prem locations only). - `type` - (String) The type of network. - `user_tags` - (List) List of user tags attached to the resource. - `vlan_id` - (String) The VLAN ID that the network is connected to. diff --git a/website/docs/r/code_engine_app.html.markdown b/website/docs/r/code_engine_app.html.markdown index c39b27c3f0..9db4e5958b 100644 --- a/website/docs/r/code_engine_app.html.markdown +++ b/website/docs/r/code_engine_app.html.markdown @@ -124,6 +124,7 @@ Nested schema for **run_volume_mounts**: * `scale_concurrency` - (Optional, Integer) Optional maximum number of requests that can be processed concurrently per instance. * Constraints: The default value is `100`. * `scale_concurrency_target` - (Optional, Integer) Optional threshold of concurrent requests per instance at which one or more additional instances are created. Use this value to scale up instances based on concurrent number of requests. This option defaults to the value of the `scale_concurrency` option, if not specified. + * Constraints: The default value is `100`. The maximum value is `1000`. The minimum value is `1`. * `scale_cpu_limit` - (Optional, String) Optional number of CPU set for the instance of the app. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). * Constraints: The default value is `1`. The maximum length is `10` characters. The minimum length is `0` characters. The value must match regular expression `/^([0-9.]+)([eEinumkKMGTPB]*)$/`. * `scale_down_delay` - (Optional, Integer) Optional amount of time in seconds that delays the scale-down behavior for an app instance. diff --git a/website/docs/r/container_vpc_cluster.html.markdown b/website/docs/r/container_vpc_cluster.html.markdown index a5b2832faa..d421edd2c3 100644 --- a/website/docs/r/container_vpc_cluster.html.markdown +++ b/website/docs/r/container_vpc_cluster.html.markdown @@ -220,6 +220,7 @@ Review the argument references that you can specify for your resource. - `kms_account_id` - (Optional, String) Account ID for boot volume encryption, if other account is providing the kms. - `security_groups` - (Optional, List) Enables users to define specific security groups for their workers. - `disable_outbound_traffic_protection` - (Optional, Bool) Include this option to allow public outbound access from the cluster workers. By default, public outbound access is blocked in OpenShift versions 4.15 and later and Kubernetes versions 1.30 and later. This option is usable only from OpenShift versions 4.15 and later and Kubernetes versions 1.30 and later. +- `enable_secure_by_default` - (Optional, Bool) Enables Secure-by-default security group configuration. Once the upgrade begins, it cannot be undone. During the upgrade, network traffic to your cluster may temporarily be blocked. This option is usable only from OpenShift versions 4.15 and later and Kubernetes versions 1.30 and later. **Note** diff --git a/website/docs/r/database.html.markdown b/website/docs/r/database.html.markdown index ae9bd98c39..cb0bddec4a 100644 --- a/website/docs/r/database.html.markdown +++ b/website/docs/r/database.html.markdown @@ -733,6 +733,7 @@ Import requires a minimal Terraform config file to allow importing. ```terraform resource "ibm_database" "" { name = "" +} ``` Run `terraform state show ibm_database.` after import to retrieve the more values to be included in the resource config file. Observe the ICD exports the admin userid. It does not export any more user IDs and passwords that are configured on the instance. These values must be retrieved from an alternative source. If new passwords need to be configured or the connection string that is retrieved to use the service, a new users block must be defined to create new users. This limitation is due to a lack of ICD functionality. diff --git a/website/docs/r/db2_instance.html.markdown b/website/docs/r/db2_instance.html.markdown new file mode 100644 index 0000000000..854359b7b5 --- /dev/null +++ b/website/docs/r/db2_instance.html.markdown @@ -0,0 +1,135 @@ +--- +subcategory: "Db2 SaaS" +layout: "ibm" +page_title: "IBM : ibm_db2" +description: |- + Manages IBM Db2 SaaS instance. +--- + +# ibm_db2 + +Create or delete an IBM Db2 SaaS on IBM Cloud instance. The `ibmcloud_api_key` that are used by Terraform should grant IAM rights to create and modify IBM Cloud Db2 Databases and have access to the resource group the Db2 SaaS instance is associated with. For more information, see [documentation](https://cloud.ibm.com/docs/Db2onCloud?topic=Db2onCloud-getting-started) to manage Db2 SaaS instances. + + +Configuration of an Db2 SaaS resource requires that the `region` parameter is set for the IBM provider in the `provider.tf` to be the same as the target Db2 SaaS `location/region`. If the Terraform configuration needs to deploy resources into multiple regions, provider alias can be used. For more information, see [Terraform provider configuration](https://www.terraform.io/docs/configuration/providers.html#multiple-provider-instances). + + +## Example usage +To find an example for provisioning and configuring a Db2 SaaS instance , see [here](https://github.com/IBM-Cloud/terraform-provider-ibm/tree/master/examples/ibm-db2). + +```terraform +data "ibm_resource_group" "group" { + name = "" +} + +resource "ibm_db2" "" { + name = "" + service = "dashdb-for-transactions" + plan = "performance" + location = "us-south" + resource_group_id = data.ibm_resource_group.group.id + service_endpoints = "public-and-private" + instance_type = "bx2.4x16" + high_availability = "yes" + backup_location = "us" + + parameters_json = <:key:`. `backup_encryption_key_crn` can be added only at the time of creation and no update support are available. + + +## Attribute reference +In addition to all argument references list, you can access the following attribute references after your resource is created. + +- `id` - (String) The CRN of the database instance. +- `status` - (String) The status of the instance. +- `version` - (String) The database version. + +## Import +The database instance can be imported by using the ID, that is formed from the CRN. To import the resource, you must specify the `region` parameter in the `provider` block of your Terraform configuration file. If the region is not specified, `us-south` is used by default. An Terraform refresh or apply fails, if the database instance is not in the same region as configured in the provider or its alias. + +CRN is a 120 digit character string of the form - `crn:v1:bluemix:public:dashdb-for-transactions:us-south:a/60970f92286548d8a64cbb45bce39bc1:deae06ff-3966-4534-bfa0-4b42281e7cef::` + +**Syntax** + +``` +$ terraform import ibm_db2.my_db +``` + +**Example** + +``` +$ terraform import ibm_db2.my_db crn:v1:bluemix:public:dashdb-for-transactions:us-south:a/60970f92286548d8a64cbb45bce39bc1:deae06ff-3966-4534-bfa0-4b42281e7cef:: +``` + +Import requires a minimal Terraform config file to allow importing. + +```terraform +resource "ibm_db2" "" { + name = "" +} +``` + +Run `terraform state show ibm_db2.` after import to retrieve the more values to be included in the resource config file. It does not export any more user IDs and passwords that are configured on the instance. These values must be retrieved from an alternative source. \ No newline at end of file diff --git a/website/docs/r/is_bare_metal_server.markdown b/website/docs/r/is_bare_metal_server.markdown index 0d5ae468d1..e999bf4e9d 100644 --- a/website/docs/r/is_bare_metal_server.markdown +++ b/website/docs/r/is_bare_metal_server.markdown @@ -56,6 +56,53 @@ resource "ibm_is_bare_metal_server" "example" { } vpc = ibm_is_vpc.example.id } +``` +### Reservation Example +```terraform +resource "ibm_is_reservation" "example" { + capacity { + total = 5 + } + committed_use { + term = "one_year" + } + profile { + name = "mx2d-metal-32x192" + resource_type = "bare_metal_server_profile" + } + zone = "us-east-3" + name = "reservation-name" +} +resource "ibm_is_vpc" "example" { + name = "example-vpc" +} +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.vpc.id + zone = "us-south-3" + ipv4_cidr_block = "10.240.129.0/24" +} +resource "ibm_is_ssh_key" "example" { + name = "example-ssh" + public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR" +} +resource "ibm_is_bare_metal_server" "example" { + profile = "mx2d-metal-32x192" + name = "example-bms" + image = "r134-31c8ca90-2623-48d7-8cf7-737be6fc4c3e" + zone = "us-south-3" + keys = [ibm_is_ssh_key.example.id] + primary_network_interface { + subnet = ibm_is_subnet.example.id + } + reservation_affinity { + policy = "manual" + pool { + id = ibm_is_reservation.example.id + } + } + vpc = ibm_is_vpc.example.id +} ``` ### Reserved ip example @@ -141,6 +188,13 @@ Review the argument references that you can specify for your resource. - `bandwidth` - (Integer) The total bandwidth (in megabits per second) shared across the bare metal server's network interfaces. The specified value must match one of the bandwidth values in the bare metal server's profile. - `delete_type` - (Optional, String) Type of deletion on destroy. **soft** signals running operating system to quiesce and shutdown cleanly, **hard** immediately stop the server. By default its `hard`. - `enable_secure_boot` - (Optional, Boolean) Indicates whether secure boot is enabled. If enabled, the image must support secure boot or the server will fail to boot. Updating `enable_secure_boot` requires the server to be stopped and then it would be started. +- `health_reasons` - (List) The reasons for the current health_state (if any). + + Nested scheme for `health_reasons`: + - `code` - (String) A snake case string succinctly identifying the reason for this health state. + - `message` - (String) An explanation of the reason for this health state. + - `more_info` - (String) Link to documentation about the reason for this health state. +- `health_state` - (String) The health of this resource. - `image` - (Required, String) ID of the image. ( On update of `image`, server will be [reinitialized](https://cloud.ibm.com/apidocs/vpc/latest#replace-bare-metal-server-initialization) if server is in stopped state, else server will be stopped and restarted during update ) -> **NOTE:** @@ -288,6 +342,31 @@ Review the argument references that you can specify for your resource. - `subnet` - (Required, String) ID of the subnet to associate with. - `profile` - (Required, Forces new resource, String) The name the profile to use for this bare metal server. +- `reservation`- (List) The reservation used by this bare metal server. + Nested scheme for `reservation`: + - `crn` - (String) The CRN for this reservation. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted, and provides some supplementary information. + + Nested `deleted` blocks have the following structure: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this reservation. + - `id` - (String) The unique identifier for this reservation. + - `name` - (string) The name for this reservation. The name is unique across all reservations in the region. + - `resource_type` - (string) The resource type. +- `reservation_affinity`- (List) The bare metal server reservation affinity. + + Nested scheme for `reservation_affinity`: + - `policy` - (String) The reservation affinity policy to use for this bare metal server. + - `pool` - (List) The pool of reservations available for use by this bare metal server. + Nested `pool` blocks have the following structure: + - `crn` - (String) The CRN for this reservation. + - `deleted` - (List) If present, this property indicates the referenced resource has been deleted, and provides some supplementary information. + Nested `deleted` blocks have the following structure: + - `more_info` - (String) Link to documentation about deleted resources. + - `href` - (String) The URL for this reservation. + - `id` - (String) The unique identifier for this reservation. + - `name` - (string) The name for this reservation. The name is unique across all reservations in the region. + - `resource_type` - (string) The resource type. - `resource_group` - (Optional, Forces new resource, String) The resource group ID for this bare metal server. - `trusted_platform_module` - (Optional, List) trusted platform module (TPM) configuration for the bare metals server @@ -339,6 +418,16 @@ In addition to all argument reference list, you can access the following attribu - `subnet` - (String) ID of the subnet to associate with. - `vlan` - (Integer) Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this interface. [ conflicts with `allowed_vlans`] +- `reservation_affinity` - (Optional, List) The reservation affinity for the bare metal server + Nested scheme for `reservation_affinity`: + - `policy` - (Optional, String) The reservation affinity policy to use for this bare metal server. + + ->**policy** + • disabled: Reservations will not be used +
• manual: Reservations in pool will be available for use + - `pool` - (Optional, String) The pool of reservations available for use by this bare metal server. Specified reservations must have a status of active, and have the same profile and zone as this bare metal server. The pool must be empty if policy is disabled, and must not be empty if policy is manual. + Nested scheme for `pool`: + - `id` - The unique identifier for this reservation - `resource_type` - (String) The type of resource. - `firmware_update_type_available` - (String) The firmware update type available for the bare metal server. -> **Supported firmware update types**
• none
• optional
• required diff --git a/website/docs/r/is_cluster_network.html.markdown b/website/docs/r/is_cluster_network.html.markdown new file mode 100644 index 0000000000..5d8b690c08 --- /dev/null +++ b/website/docs/r/is_cluster_network.html.markdown @@ -0,0 +1,78 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_cluster_network" +description: |- + Manages ClusterNetwork. +subcategory: "VPC infrastructure" +--- + +# ibm_is_cluster_network + +Create, update, and delete ClusterNetworks with this resource. + +~>**Select Availability** +Cluster Networks for VPC is available for select customers only. Contact IBM Support if you are interested in using this functionality. [About cluster networks](https://cloud.ibm.com/docs/vpc?topic=vpc-about-cluster-network) + +## Example Usage + +```hcl +resource "ibm_is_cluster_network" "example" { + name = "my-cluster-network" + profile = "h100" + resource_group = "fee82deba12e4c0fb69c3b09d1f12345" + subnet_prefixes { + cidr = "10.0.0.0/24" + } + vpc { + id = "r006-4727d842-f94f-4a2d-824a-9bc9b02c523b" + } + zone = "us-east-3" +} + +``` + +## Argument Reference + +You can specify the following arguments for this resource. + +- `name` - (Optional, String) The name for this cluster network. The name must not be used by another cluster network in the region. +- `profile` - (Required, String) The profile (globally unique name for the cluster network profile) for this cluster network. +- `resource_group` - (Optional, String) The resource group (unique identifier for the resource group) for this cluster network. +- `subnet_prefixes` - (Optional, List) The IP address ranges available for subnets for this cluster network.(The maximum length is `1` item. The minimum length is `1` item.) + Nested schema for **subnet_prefixes**: + - `cidr` - (Required, String) The CIDR block for this prefix. +- `vpc` - (Required, List) The VPC this cluster network resides in. + Nested schema for **vpc**: + - `id` - (Required, String) The unique identifier for this VPC. +- `zone` - (Required, List) The zone (globally unique name for this zone) this cluster network resides in. + +## 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 ClusterNetwork. +- `created_at` - (String) The date and time that the cluster network was created. +- `crn` - (String) The CRN for this cluster network. +- `href` - (String) The URL for this cluster network. +- `lifecycle_reasons` - (List) The reasons for the current `lifecycle_state` (if any). + Nested schema for **lifecycle_reasons**: + - `code` - (String) A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. Allowable values are: `internal_error`, `resource_suspended_by_provider`. + - `message` - (String) An explanation of the reason for this lifecycle state. + - `more_info` - (String) Link to documentation about the reason for this lifecycle state. +- `lifecycle_state` - (String) The lifecycle state of the cluster network. Allowable values are: `deleting`, `failed`, `pending`, `stable`, `suspended`, `updating`, `waiting`. +- `resource_type` - (String) The resource type. Allowable values are: `cluster_network`. +- `etag` - ETag identifier for ClusterNetwork. + +## Import + +You can import the `ibm_is_cluster_network` resource by using `id`. The unique identifier for this cluster network. + +# Syntax +
+$ terraform import ibm_is_cluster_network.is_cluster_network <id>
+
+ +# Example +``` +$ terraform import ibm_is_cluster_network.is_cluster_network 0717-da0df18c-7598-4633-a648-fdaac28a5573 +``` diff --git a/website/docs/r/is_cluster_network_interface.html.markdown b/website/docs/r/is_cluster_network_interface.html.markdown new file mode 100644 index 0000000000..3b4e036641 --- /dev/null +++ b/website/docs/r/is_cluster_network_interface.html.markdown @@ -0,0 +1,109 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_cluster_network_interface" +description: |- + Manages ClusterNetworkInterface. +subcategory: "VPC infrastructure" +--- + +# ibm_is_cluster_network_interface + +Create, update, and delete ClusterNetworkInterfaces with this resource. + +## Example Usage + +~>**Select Availability** +Cluster Networks for VPC is available for select customers only. Contact IBM Support if you are interested in using this functionality. [About cluster networks](https://cloud.ibm.com/docs/vpc?topic=vpc-about-cluster-network) + + +```hcl +resource "ibm_is_cluster_network_interface" "is_cluster_network_interface_instance" { + cluster_network_id = "cluster_network_id" + name = "my-cluster-network-interface" + primary_ip { + address = "10.1.0.6" + name = "my-cluster-network-subnet-reserved-ip" + } + subnet { + id = "0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930" + } +} +``` + +## Argument Reference + +You can specify the following arguments for this resource. + +- `cluster_network_id` - (Required, Forces new resource, String) The cluster network identifier. +- `name` - (Optional, String) The name for this cluster network interface. The name is unique across all interfaces in the cluster network. +- `primary_ip` - (Optional, List) The cluster network subnet reserved IP for this cluster network interface. + + Nested schema for **primary_ip**: + - `address` - (Required, String) The IP address.If the address is pending allocation, the value will be `0.0.0.0`.This property may [expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) to support IPv6 addresses in the future. + - `href` - (Required, String) The URL for this cluster network subnet reserved IP. + - `id` - (Required, String) The unique identifier for this cluster network subnet reserved IP. + - `name` - (Required, String) The name for this cluster network subnet reserved IP. The name is unique across all reserved IPs in a cluster network subnet. + - `resource_type` - (Computed, String) The resource type. Allowable values are: `cluster_network_subnet_reserved_ip`. +- `subnet` - (Optional, List) The associated cluster network subnet. Required if `primary_ip` does not specify a clusternetwork subnet reserved IP identity. + + Nested schema for **subnet**: + - `href` - (Required, String) The URL for this cluster network subnet. + - `id` - (Required, String) The unique identifier for this cluster network subnet. + +## 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 ClusterNetworkInterface. +- `allow_ip_spoofing` - (Boolean) Indicates whether source IP spoofing is allowed on this cluster network interface. If `false`, source IP spoofing is prevented on this cluster network interface. If `true`, source IP spoofing is allowed on this cluster network interface. +- `auto_delete` - (Boolean) Indicates whether this cluster network interface will be automatically deleted when `target` is deleted. +- `created_at` - (String) The date and time that the cluster network interface was created. +- `enable_infrastructure_nat` - (Boolean) If `true`:- The VPC infrastructure performs any needed NAT operations.- `floating_ips` must not have more than one floating IP.If `false`:- Packets are passed unchanged to/from the virtual network interface, allowing the workload to perform any needed NAT operations. +- `href` - (String) The URL for this cluster network interface. +- `cluster_network_interface_id` - (String) The unique identifier for this cluster network interface. +- `lifecycle_reasons` - (List) The reasons for the current `lifecycle_state` (if any). + Nested schema for **lifecycle_reasons**: + - `code` - (String) A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. Allowable values are: `internal_error`, `resource_suspended_by_provider`. + - `message` - (String) An explanation of the reason for this lifecycle state. + - `more_info` - (String) Link to documentation about the reason for this lifecycle state. +- `lifecycle_state` - (String) The lifecycle state of the cluster network interface. Allowable values are: `deleting`, `failed`, `pending`, `stable`, `suspended`, `updating`, `waiting`. +- `mac_address` - (String) The MAC address of the cluster network interface. May be absent if`lifecycle_state` is `pending`. +- `resource_type` - (String) The resource type. llowable values are: `cluster_network_interface`. +- `target` - (List) The target of this cluster network interface.If absent, this cluster network interface is not attached to a target.The resources supported by this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + Nested schema for **target**: + - `href` - (String) The URL for this instance cluster network attachment. + - `id` - (String) The unique identifier for this instance cluster network attachment. + - `name` - (String) The name for this instance cluster network attachment. The name is unique across all network attachments for the instance. + - `resource_type` - (String) The resource type. Allowable values are: `instance_cluster_network_attachment`. +- `vpc` - (List) The VPC this cluster network interface resides in. + Nested schema for **vpc**: + - `crn` - (String) The CRN for this VPC. + - `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 VPC. + - `id` - (String) The unique identifier for this VPC. + - `name` - (String) The name for this VPC. The name is unique across all VPCs in the region. + - `resource_type` - (String) The resource type. Allowable values are: `vpc`. +- `zone` - (List) The zone this cluster network interface resides in. + Nested schema for **zone**: + - `href` - (String) The URL for this zone. + - `name` - (String) The globally unique name for this zone. + +- `etag` - ETag identifier for ClusterNetworkInterface. + +## Import + +You can import the `ibm_is_cluster_network_interface` resource by using `id`. +The `id` property can be formed from `cluster_network_id`, and `cluster_network_interface_id` in the following format: + +
+<cluster_network_id>/<cluster_network_interface_id>
+
+- `cluster_network_id`: A string. The cluster network identifier. +- `cluster_network_interface_id`: A string in the format `0717-ffc092f7-5d02-4b93-ab69-26860529b9fb`. The unique identifier for this cluster network interface. + +# Syntax +
+$ terraform import ibm_is_cluster_network_interface.is_cluster_network_interface <cluster_network_id>/<cluster_network_interface_id>
+
diff --git a/website/docs/r/is_cluster_network_subnet.html.markdown b/website/docs/r/is_cluster_network_subnet.html.markdown new file mode 100644 index 0000000000..bf9ec3f2bc --- /dev/null +++ b/website/docs/r/is_cluster_network_subnet.html.markdown @@ -0,0 +1,76 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_cluster_network_subnet" +description: |- + Manages ClusterNetworkSubnet. +subcategory: "VPC infrastructure" +--- + +# ibm_is_cluster_network_subnet + +Create, update, and delete ClusterNetworkSubnets with this resource. + +~>**Select Availability** +Cluster Networks for VPC is available for select customers only. Contact IBM Support if you are interested in using this functionality. [About cluster networks](https://cloud.ibm.com/docs/vpc?topic=vpc-about-cluster-network) + +## Example Usage + +```hcl +resource "ibm_is_cluster_network_subnet" "is_cluster_network_subnet_instance" { + cluster_network_id = "cluster_network_id" + ip_version = "ipv4" + ipv4_cidr_block = "10.0.0.0/24" + name = "my-cluster-network-subnet" + # total_ipv4_address_count = 256 // either ipv4_cidr_block or total_ipv4_address_count +} +``` + +## Argument Reference + +You can specify the following arguments for this resource. + +- `cluster_network_id` - (Required, Forces new resource, String) The cluster network identifier. +- `ip_version` - (Optional, String) The IP version for this cluster network subnet.The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. Allowable values are: `ipv4`. +- `ipv4_cidr_block` - (Optional, String) The IPv4 range of this cluster network subnet, expressed in CIDR format. +- `name` - (Optional, String) The name for this cluster network subnet. The name is unique across all cluster network subnets in the cluster network. +- `total_ipv4_address_count` - (Optional, Integer) The total number of IPv4 addresses in this cluster network subnet.Note: This is calculated as 2(32 - prefix length). For example, the prefix length `/24` gives:
2(32 - 24) = 28 = 256 addresses. + +## 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 ClusterNetworkSubnet. +- `available_ipv4_address_count` - (Integer) The number of IPv4 addresses in this cluster network subnet that are not in use, and have not been reserved by the user or the provider. +- `created_at` - (String) The date and time that the cluster network subnet was created. +- `href` - (String) The URL for this cluster network subnet. +- `cluster_network_subnet_id` - (String) The unique identifier for this cluster network subnet. +- `lifecycle_reasons` - (List) The reasons for the current `lifecycle_state` (if any). + + Nested schema for **lifecycle_reasons**: + - `code` - (String) A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. + * Constraints: Allowable values are: `internal_error`, `resource_suspended_by_provider`. + - `message` - (String) An explanation of the reason for this lifecycle state. + - `more_info` - (String) Link to documentation about the reason for this lifecycle state. + * Constraints: The maximum length is `8000` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. +- `lifecycle_state` - (String) The lifecycle state of the cluster network subnet. + * Constraints: Allowable values are: `deleting`, `failed`, `pending`, `stable`, `suspended`, `updating`, `waiting`. +- `resource_type` - (String) The resource type. + * Constraints: Allowable values are: `cluster_network_subnet`. + +- `etag` - ETag identifier for ClusterNetworkSubnet. + +## Import + +You can import the `ibm_is_cluster_network_subnet` resource by using `id`. +The `id` property can be formed from `cluster_network_id`, and `cluster_network_subnet_id` in the following format: + +
+<cluster_network_id>/<cluster_network_subnet_id>
+
+- `cluster_network_id`: A string. The cluster network identifier. +- `cluster_network_subnet_id`: A string in the format `0717-7931845c-65c4-4b0a-80cd-7d9c1a6d7930`. The unique identifier for this cluster network subnet. + +# Syntax +
+$ terraform import ibm_is_cluster_network_subnet.is_cluster_network_subnet <cluster_network_id>/<cluster_network_subnet_id>
+
diff --git a/website/docs/r/is_cluster_network_subnet_reserved_ip.html.markdown b/website/docs/r/is_cluster_network_subnet_reserved_ip.html.markdown new file mode 100644 index 0000000000..2a97df6f92 --- /dev/null +++ b/website/docs/r/is_cluster_network_subnet_reserved_ip.html.markdown @@ -0,0 +1,79 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_cluster_network_subnet_reserved_ip" +description: |- + Manages ClusterNetworkSubnetReservedIP. +subcategory: "VPC infrastructure" +--- + +# ibm_is_cluster_network_subnet_reserved_ip + +Create, update, and delete ClusterNetworkSubnetReservedIPs with this resource. + +~>**Select Availability** +Cluster Networks for VPC is available for select customers only. Contact IBM Support if you are interested in using this functionality. [About cluster networks](https://cloud.ibm.com/docs/vpc?topic=vpc-about-cluster-network) + +## Example Usage + +```hcl +resource "ibm_is_cluster_network_subnet_reserved_ip" "is_cluster_network_subnet_reserved_ip_instance" { + address = "192.168.3.4" + cluster_network_id = "cluster_network_id" + cluster_network_subnet_id = "cluster_network_subnet_id" + name = "my-cluster-network-subnet-reserved-ip" +} +``` + +## Argument Reference + +You can specify the following arguments for this resource. + +- `address` - (Optional, String) The IP address.If the address is pending allocation, the value will be `0.0.0.0`.This property may [expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) to support IPv6 addresses in the future. +- `cluster_network_id` - (Required, Forces new resource, String) The cluster network identifier. +- `cluster_network_subnet_id` - (Required, Forces new resource, String) The cluster network subnet identifier. +- `name` - (Optional, String) The name for this cluster network subnet reserved IP. The name is unique across all reserved IPs in a cluster network subnet. + +## 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 ClusterNetworkSubnetReservedIP. +- `auto_delete` - (Boolean) Indicates whether this cluster network subnet reserved IP member will be automatically deleted when either `target` is deleted, or the cluster network subnet reserved IP is unbound. +- `created_at` - (String) The date and time that the cluster network subnet reserved IP was created. +- `href` - (String) The URL for this cluster network subnet reserved IP. +- `cluster_network_subnet_reserved_ip_id` - (String) The unique identifier for this cluster network subnet reserved IP. +- `lifecycle_reasons` - (List) The reasons for the current `lifecycle_state` (if any). + Nested schema for **lifecycle_reasons**: + - `code` - (String) A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. Allowable values are: `internal_error`, `resource_suspended_by_provider`. + - `message` - (String) An explanation of the reason for this lifecycle state. + - `more_info` - (String) Link to documentation about the reason for this lifecycle state. +- `lifecycle_state` - (String) The lifecycle state of the cluster network subnet reserved IP. Allowable values are: `deleting`, `failed`, `pending`, `stable`, `suspended`, `updating`, `waiting`. +- `owner` - (String) The owner of the cluster network subnet reserved IPThe enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. Allowable values are: `provider`, `user`. +- `resource_type` - (String) The resource type. Allowable values are: `cluster_network_subnet_reserved_ip`. +- `target` - (List) The target this cluster network subnet reserved IP is bound to.If absent, this cluster network subnet reserved IP is provider-owned or unbound. + Nested schema for **target**: + - `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 cluster network interface. + - `id` - (String) The unique identifier for this cluster network interface. + - `name` - (String) The name for this cluster network interface. The name is unique across all interfaces in the cluster network. + - `resource_type` - (String) The resource type. Allowable values are: `cluster_network_interface`. +- `etag` - ETag identifier for ClusterNetworkSubnetReservedIP. + +## Import + +You can import the `ibm_is_cluster_network_subnet_reserved_ip` resource by using `id`. +The `id` property can be formed from `cluster_network_id`, `cluster_network_subnet_id`, and `cluster_network_subnet_reserved_ip_id` in the following format: + +
+<cluster_network_id>/<cluster_network_subnet_id>/<cluster_network_subnet_reserved_ip_id>
+
+- `cluster_network_id`: A string. The cluster network identifier. +- `cluster_network_subnet_id`: A string. The cluster network subnet identifier. +- `cluster_network_subnet_reserved_ip_id`: A string in the format `6d353a0f-aeb1-4ae1-832e-1110d10981bb`. The unique identifier for this cluster network subnet reserved IP. + +# Syntax +
+$ terraform import ibm_is_cluster_network_subnet_reserved_ip.is_cluster_network_subnet_reserved_ip <cluster_network_id>/<cluster_network_subnet_id>/<cluster_network_subnet_reserved_ip_id>
+
diff --git a/website/docs/r/is_instance.html.markdown b/website/docs/r/is_instance.html.markdown index 4293929715..e2398ebcb9 100644 --- a/website/docs/r/is_instance.html.markdown +++ b/website/docs/r/is_instance.html.markdown @@ -486,6 +486,94 @@ resource "ibm_is_instance" "example" { } } ``` +### Example to create an instance with cluster network attachments ### + +```terraform + +resource "ibm_is_instance" "is_instance" { + name = "example-instance" + image = data.ibm_is_image.example.id + profile = "gx3d-160x1792x8h100" + primary_network_interface { + subnet = ibm_is_subnet.example.id + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-1" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-2" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-3" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-4" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-5" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-6" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-7" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + cluster_network_attachments { + cluster_network_interface{ + auto_delete = true + name = "cna-8" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + } + vpc = ibm_is_vpc.example.id + zone = ibm_is_subnet.example.zone + keys = [ibm_is_ssh_key.example.id] +} +``` ## Timeouts The `ibm_is_instance` resource provides the following [[Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: @@ -544,6 +632,18 @@ Review the argument references that you can specify for your resource. ~> **Note:** `offering_crn` conflicts with `version_crn`, both are mutually exclusive. `catalog_offering` and `image` id are mutually exclusive. `snapshot` conflicts with `image` id and `instance_template` + +~>**Select Availability** +Cluster Networks for VPC is available for select customers only. Contact IBM Support if you are interested in using this functionality. [About cluster networks](https://cloud.ibm.com/docs/vpc?topic=vpc-about-cluster-network) + +- `cluster_network_attachments` - (Optional, List) The cluster network attachments for this virtual server instance.The cluster network attachments are ordered for consistent instance configuration. + + Nested schema for **cluster_network_attachments**: + - `href` - (Required, String) The URL for this instance cluster network attachment. + - `id` - (Required, String) The unique identifier for this instance cluster network attachment. + - `name` - (Required, String) The name for this instance cluster network attachment. The name is unique across all network attachments for the instance. + - `resource_type` - (Required, String) The resource type. + - `confidential_compute_mode` - (Optional, String) The confidential compute mode to use for this virtual server instance.If unspecified, the default confidential compute mode from the profile will be used. **Constraints: Allowable values are: `disabled`, `sgx`** {Select Availability} ~>**Note:** The confidential_compute_mode is `Select Availability` feature. Confidential computing with Intel SGX for VPC is available only in the US-South (Dallas) region. @@ -735,7 +835,16 @@ Review the argument references that you can specify for your resource. - `tags` (Optional, Array of Strings) A list of tags that you want to add to your instance. Tags can help you find your instance more easily later. - `total_volume_bandwidth` - (Optional, Integer) The amount of bandwidth (in megabits per second) allocated exclusively to instance storage volumes - `user_data` - (Optional, String) User data to transfer to the instance. For more information, about `user_data`, see [about user data](https://cloud.ibm.com/docs/vpc?topic=vpc-user-data). -- `volumes` (Optional, List) A comma separated list of volume IDs to attach to the instance. +- `volumes` (Optional, List) A comma separated list of volume IDs to attach to the instance. Mutually exclusive with `volume_prototypes`. +- `volume_prototypes`- (List of Strings) A list of data volumes to attach to the instance. Mutually exclusive with `volumes`. + + Nested scheme for `volume_prototypes`: + - `delete_volume_on_instance_delete` - (Bool) If set to **true**, automatically deletes the volumes that are attached to an instance. **Note** Setting this argument can bring some inconsistency in the volume resource, as the volumes is destroyed along with instances. + - `encryption` - (String) The type of encryption that is used for the volume prototype. + - `iops`- (Integer) The number of input and output operations per second of the volume prototype. + - `name` - (String) The name of the volume prototype. + - `profile` - (String) The profile of the volume prototype. + - `size`- (Integer) The capacity of the volume in gigabytes. - `vpc` - (Required, Forces new resource, String) The ID of the VPC where you want to create the instance. When using `instance_template`, `vpc` is not required. - `zone` - (Required, Forces new resource, String) The name of the VPC zone where you want to create the instance. When using `instance_template`, `zone` is not required. @@ -760,6 +869,18 @@ In addition to all argument reference list, you can access the following attribu - `deleted` - (List) If present, this property indicates the referenced resource has been deleted, and provides some supplementary information. Nested schema for `deleted`: - `more_info` - (String) Link to documentation about deleted resources. + +- `cluster_network` - (List) If present, the cluster network that this virtual server instance resides in. + Nested schema for **cluster_network**: + - `crn` - (String) The CRN for this cluster network. + - `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 cluster network. + - `id` - (String) The unique identifier for this cluster network. + - `name` - (String) The name for this cluster network. The name must not be used by another cluster network in the region. + - `resource_type` - (String) The resource type. + - `crn` - (String) The CRN of the instance. - `disks` - (List of Strings) The collection of the instance's disks. Nested `disks` blocks have the following structure: @@ -778,6 +899,13 @@ In addition to all argument reference list, you can access the following attribu - `manufacture` - (String) The manufacturer of the GPU. - `memory`- (Integer) The amount of memory of the GPU in gigabytes. - `model` - (String) The model of the GPU. +- `health_reasons` - (List) The reasons for the current health_state (if any). + + Nested scheme for `health_reasons`: + - `code` - (String) A snake case string succinctly identifying the reason for this health state. + - `message` - (String) An explanation of the reason for this health state. + - `more_info` - (String) Link to documentation about the reason for this health state. +- `health_state` - (String) The health of this resource. - `placement_target` - The placement restrictions for the virtual server instance. - `crn` - The CRN of the placement target - `deleted` - If present, this property indicates the referenced resource has been deleted and providessome supplementary information. diff --git a/website/docs/r/is_instance_cluster_network_attachment.html.markdown b/website/docs/r/is_instance_cluster_network_attachment.html.markdown new file mode 100644 index 0000000000..15517fb9b6 --- /dev/null +++ b/website/docs/r/is_instance_cluster_network_attachment.html.markdown @@ -0,0 +1,221 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_is_instance_cluster_network_attachment" +description: |- + Manages InstanceClusterNetworkAttachment. +subcategory: "VPC infrastructure" +--- + +# ibm_is_instance_cluster_network_attachment + +Create, update, and delete InstanceClusterNetworkAttachments with this resource. + +~>**Select Availability** +Cluster Networks for VPC is available for select customers only. Contact IBM Support if you are interested in using this functionality. [About cluster networks](https://cloud.ibm.com/docs/vpc?topic=vpc-about-cluster-network) + +## Example Usage + +```hcl + +resource "ibm_is_instance_action" "is_instance_stop_before" { + action = "stop" + instance = ibm_is_instance.is_instance.id +} + +resource "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance" { + depends_on = [ibm_is_instance_action.is_instance_stop_before] + instance_id = ibm_is_instance.is_instance.id + before { + id = ibm_is_instance.is_instance.cluster_network_attachments.0.id + } + cluster_network_interface { + name = "my-cluster-network-interface" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + name = "cna-9" +} +resource "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance10" { + depends_on = [ibm_is_instance_action.is_instance_stop_before] + instance_id = ibm_is_instance.is_instance.id + before { + id = ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance.instance_cluster_network_attachment_id + } + cluster_network_interface { + name = "my-cluster-network-interface-10" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + name = "cna-10" +} +resource "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance11" { + depends_on = [ibm_is_instance_action.is_instance_stop_before] + instance_id = ibm_is_instance.is_instance.id + before { + id = ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance10.instance_cluster_network_attachment_id +} + cluster_network_interface { + name = "my-cluster-network-interface-11" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + name = "cna-11" +} +resource "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance12" { + depends_on = [ibm_is_instance_action.is_instance_stop_before] + instance_id = ibm_is_instance.is_instance.id + before { + id = ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance11.instance_cluster_network_attachment_id +} + cluster_network_interface { + name = "my-cluster-network-interface12" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + name = "cna-12" +} +resource "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance13" { + depends_on = [ibm_is_instance_action.is_instance_stop_before] + instance_id = ibm_is_instance.is_instance.id + before { + id = ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance12.instance_cluster_network_attachment_id + } + cluster_network_interface { + name = "my-cluster-network-interface13" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + name = "cna-13" +} +resource "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance14" { + depends_on = [ibm_is_instance_action.is_instance_stop_before] + instance_id = ibm_is_instance.is_instance.id + before { + id = ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance13.instance_cluster_network_attachment_id + } + cluster_network_interface { + name = "my-cluster-network-interface14" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + name = "cna-149" +} +resource "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance15" { + depends_on = [ibm_is_instance_action.is_instance_stop_before] + instance_id = ibm_is_instance.is_instance.id + before { + id = ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance14.instance_cluster_network_attachment_id + } + cluster_network_interface { + name = "my-cluster-network-interface15" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + name = "cna-15" +} +resource "ibm_is_instance_cluster_network_attachment" "is_instance_cluster_network_attachment_instance16" { + depends_on = [ibm_is_instance_action.is_instance_stop_before] + instance_id = ibm_is_instance.is_instance.id + before { + id = ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance15.instance_cluster_network_attachment_id + } + cluster_network_interface { + name = "my-cluster-network-interface16" + subnet { + id = ibm_is_cluster_network_subnet.is_cluster_network_subnet_instance.cluster_network_subnet_id + } + } + name = "cna-16" +} +resource "ibm_is_instance_action" "is_instance_start_after" { + # depends_on = [ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment_instance16] + action = "start" + instance = ibm_is_instance.is_instance.id +} +``` + +## Argument Reference + +You can specify the following arguments for this resource. + +- `before` - (Optional, List) The instance cluster network attachment that is immediately before. If absent, this is thelast instance cluster network attachment. + Nested schema for **before**: + - `href` - (Required, String) The URL for this instance cluster network attachment. + - `id` - (Required, String) The unique identifier for this instance cluster network attachment. + - `name` - (Computed, String) The name for this instance cluster network attachment. The name is unique across all network attachments for the instance. + - `resource_type` - (Computed, String) The resource type. +- `cluster_network_interface` - (Required, List) The cluster network interface for this instance cluster network attachment. + + Nested schema for **cluster_network_interface**: + - `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted, and providessome supplementary information. + Nested schema for **deleted**: + - `more_info` - (Computed, String) Link to documentation about deleted resources. + - `href` - (Required, String) The URL for this cluster network interface. + - `id` - (Required, String) The unique identifier for this cluster network interface. + - `name` - (Required, String) The name for this cluster network interface. The name is unique across all interfaces in the cluster network. + - `primary_ip` - (Required, List) The primary IP for this cluster network interface. + + Nested schema for **primary_ip**: + - `address` - (Required, String) The IP address.If the address is pending allocation, the value will be `0.0.0.0`.This property may [expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) to support IPv6 addresses in the future. + - `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted, and providessome supplementary information. + + Nested schema for **deleted**: + - `more_info` - (Computed, String) Link to documentation about deleted resources. + - `href` - (Required, String) The URL for this cluster network subnet reserved IP. + - `id` - (Required, String) The unique identifier for this cluster network subnet reserved IP. + - `name` - (Required, String) The name for this cluster network subnet reserved IP. The name is unique across all reserved IPs in a cluster network subnet. + - `resource_type` - (Computed, String) The resource type. + - `resource_type` - (Computed, String) The resource type. + - `subnet` - (Required, List) + + Nested schema for **subnet**: + - `deleted` - (Optional, List) If present, this property indicates the referenced resource has been deleted, and providessome supplementary information. + + Nested schema for **deleted**: + - `more_info` - (Computed, String) Link to documentation about deleted resources. + - `href` - (Required, String) The URL for this cluster network subnet. + - `id` - (Required, String) The unique identifier for this cluster network subnet. + - `name` - (Computed, String) The name for this cluster network subnet. The name is unique across all cluster network subnets in the cluster network. + - `resource_type` - (Computed, String) The resource type. +- `instance_id` - (Required, Forces new resource, String) The virtual server instance identifier. +- `name` - (Optional, String) The name for this instance cluster network attachment. The name is unique across all network attachments for the instance. + +## 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 InstanceClusterNetworkAttachment. +- `href` - (String) The URL for this instance cluster network attachment. +- `instance_cluster_network_attachment_id` - (String) The unique identifier for this instance cluster network attachment. +- `lifecycle_reasons` - (List) The reasons for the current `lifecycle_state` (if any). + + Nested schema for **lifecycle_reasons**: + - `code` - (String) A reason code for this lifecycle state:- `internal_error`: internal error (contact IBM support)- `resource_suspended_by_provider`: The resource has been suspended (contact IBM support)The enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future. Allowable values are: `internal_error`, `resource_suspended_by_provider`. + - `message` - (String) An explanation of the reason for this lifecycle state. + - `more_info` - (String) Link to documentation about the reason for this lifecycle state. +- `lifecycle_state` - (String) The lifecycle state of the instance cluster network attachment. Allowable values are: `deleting`, `failed`, `pending`, `stable`, `suspended`, `updating`, `waiting`. +- `resource_type` - (String) The resource type. Allowable values are: `instance_cluster_network_attachment`. + + +## Import + +You can import the `ibm_is_instance_cluster_network_attachment` resource by using `id`. +The `id` property can be formed from `instance_id`, and `instance_cluster_network_attachment_id` in the following format: + +
+<instance_id>/<instance_cluster_network_attachment_id>
+
+- `instance_id`: A string. The virtual server instance identifier. +- `instance_cluster_network_attachment_id`: A string in the format `0717-fb880975-db45-4459-8548-64e3995ac213`. The unique identifier for this instance cluster network attachment. + +# Syntax +
+$ terraform import ibm_is_instance_cluster_network_attachment.is_instance_cluster_network_attachment <instance_id>/<instance_cluster_network_attachment_id>
+
diff --git a/website/docs/r/is_instance_disk_management.html.markdown b/website/docs/r/is_instance_disk_management.html.markdown index 8995116656..978ab1aa6e 100644 --- a/website/docs/r/is_instance_disk_management.html.markdown +++ b/website/docs/r/is_instance_disk_management.html.markdown @@ -63,7 +63,7 @@ data "ibm_is_instance" "example" { passphrase = "" } -data "is_instance_disk" "example" { +data "ibm_is_instance_disk" "example" { instance = data.ibm_is_instance.example.id disk = data.ibm_is_instance.example.disks.0.id } diff --git a/website/docs/r/is_instance_template.html.markdown b/website/docs/r/is_instance_template.html.markdown index bf0f679468..23551255d2 100644 --- a/website/docs/r/is_instance_template.html.markdown +++ b/website/docs/r/is_instance_template.html.markdown @@ -197,7 +197,66 @@ resource "ibm_is_instance_template" "example4" { delete_volume_on_instance_delete = true } } + +// cluster_network_attachments example + +resource "ibm_is_instance_template" "is_instance_template" { + name = "example-template" + image = data.ibm_is_image.example.id + profile = "gx3d-160x1792x8h100" + primary_network_attachment { + name = ""example-template-pna" + virtual_network_interface { + auto_delete = true + subnet = ibm_is_subnet.example.id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = ibm_is_cluster_network_interface.example.cluster_network_interface_id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = ibm_is_cluster_network_interface.example.cluster_network_interface_id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = VPCibm_is_cluster_network_interface.example.cluster_network_interface_id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = VPCibm_is_cluster_network_interface.example.cluster_network_interface_id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = VPCibm_is_cluster_network_interface.example.cluster_network_interface_id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = VPCibm_is_cluster_network_interface.example.cluster_network_interface_id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = VPCibm_is_cluster_network_interface.example.cluster_network_interface_id + } + } + cluster_network_attachments { + cluster_network_interface{ + id = VPCibm_is_cluster_network_interface.example.cluster_network_interface_id + } + } + vpc = ibm_is_vpc.example.id + zone = ibm_is_subnet.example.zone + keys = [ibm_is_ssh_key.example.id] +} ``` + ## Argument reference Review the argument references that you can specify for your resource. - `availability_policy_host_failure` - (Optional, String) The availability policy to use for this virtual server instance. The action to perform if the compute host experiences a failure. Supported values are `restart` and `stop`. @@ -220,6 +279,32 @@ Review the argument references that you can specify for your resource. - `version_crn` - (Optional, Force new resource, String) The CRN for this version of a catalog offering. Identifies a version of a catalog offering by this unique property. Conflicts with `catalog_offering.0.offering_crn` - `plan_crn` - (Optional, String) The CRN for this catalog offering version's billing plan. If unspecified, no billing plan will be used (free). Must be specified for catalog offering versions that require a billing plan to be used. +~>**Select Availability** +Cluster Networks for VPC is available for select customers only. Contact IBM Support if you are interested in using this functionality. [About cluster networks](https://cloud.ibm.com/docs/vpc?topic=vpc-about-cluster-network) +- `cluster_network_attachments` - (Optional, List) The cluster network attachments to create for this virtual server instance. A cluster network attachment represents a device that is connected to a cluster network. The number of network attachments must match one of the values from the instance profile's `cluster_network_attachment_count` before the instance can be started. + + Nested schema for **cluster_network_attachments**: + - `cluster_network_interface` - (Required, List) A cluster network interface for the instance cluster network attachment. This can bespecified using an existing cluster network interface that does not already have a `target`,or a prototype object for a new cluster network interface.This instance must reside in the same VPC as the specified cluster network interface. Thecluster network interface must reside in the same cluster network as the`cluster_network_interface` of any other `cluster_network_attachments` for this instance. + Nested schema for **cluster_network_interface**: + - `auto_delete` - (Optional, Boolean) Indicates whether this cluster network interface will be automatically deleted when `target` is deleted. + - `href` - (Optional, String) The URL for this cluster network interface. + - `id` - (Optional, String) The unique identifier for this cluster network interface. + - `name` - (Optional, String) The name for this cluster network interface. The name must not be used by another interface in the cluster network. Names beginning with `ibm-` are reserved for provider-owned resources, and are not allowed. If unspecified, the name will be a hyphenated list of randomly-selected words. + - `primary_ip` - (Optional, List) The primary IP address to bind to the cluster network interface. May be eithera cluster network subnet reserved IP identity, or a cluster network subnet reserved IPprototype object which will be used to create a new cluster network subnet reserved IP.If a cluster network subnet reserved IP identity is provided, the specified clusternetwork subnet reserved IP must be unbound.If a cluster network subnet reserved IP prototype object with an address is provided,the address must be available on the cluster network interface's cluster networksubnet. If no address is specified, an available address on the cluster network subnetwill be automatically selected and reserved. + + Nested schema for **primary_ip**: + - `address` - (Optional, String) The IP address to reserve, which must not already be reserved on the subnet.If unspecified, an available address on the subnet will automatically be selected. + - `auto_delete` - (Optional, Boolean) Indicates whether this cluster network subnet reserved IP member will be automatically deleted when either `target` is deleted, or the cluster network subnet reserved IP is unbound. + - `href` - (Optional, String) The URL for this cluster network subnet reserved IP. + - `id` - (Optional, String) The unique identifier for this cluster network subnet reserved IP. + - `name` - (Optional, String) The name for this cluster network subnet reserved IP. The name must not be used by another reserved IP in the cluster network subnet. Names starting with `ibm-` are reserved for provider-owned resources, and are not allowed. If unspecified, the name will be a hyphenated list of randomly-selected words. + - `subnet` - (Optional, List) The associated cluster network subnet. Required if `primary_ip` does not specify acluster network subnet reserved IP identity. + + Nested schema for **subnet**: + - `href` - (Optional, String) The URL for this cluster network subnet. + - `id` - (Optional, String) The unique identifier for this cluster network subnet. + - `name` - (Optional, String) The name for this cluster network attachment. Names must be unique within the instance the cluster network attachment resides in. If unspecified, the name will be a hyphenated list of randomly-selected words. Names starting with `ibm-` are reserved for provider-owned resources, and are not allowed. + - `confidential_compute_mode` - (Optional, String) The confidential compute mode to use for this virtual server instance.If unspecified, the default confidential compute mode from the profile will be used. **Constraints: Allowable values are: `disabled`, `sgx`** {Select Availability} ~>**Note:** The confidential_compute_mode is `Select Availability` feature. Confidential computing with Intel SGX for VPC is available only in the US-South (Dallas) region. diff --git a/website/docs/r/mqcloud_application.html.markdown b/website/docs/r/mqcloud_application.html.markdown index 4e2341d848..fe0ae59402 100644 --- a/website/docs/r/mqcloud_application.html.markdown +++ b/website/docs/r/mqcloud_application.html.markdown @@ -3,14 +3,14 @@ layout: "ibm" page_title: "IBM : ibm_mqcloud_application" description: |- Manages mqcloud_application. -subcategory: "MQ on Cloud" +subcategory: "MQaaS" --- # ibm_mqcloud_application Create, update, and delete mqcloud_applications with this resource. -> **Note:** The MQ on Cloud Terraform provider access is restricted to users of the reserved deployment plan. +> **Note:** The MQaaS Terraform provider access is restricted to users of the reserved deployment, reserved capacity, and reserved capacity subscription plans. ## Example Usage @@ -27,7 +27,7 @@ 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. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQaaS 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 @@ -48,7 +48,7 @@ The `id` property can be formed from `service_instance_guid`, and `application_i
 <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. +* `service_instance_guid`: A string in the format `a2b4d4bc-dadb-4637-bcec-9b7d1e723af8`. The GUID that uniquely identifies the MQaaS service instance. * `application_id`: A string. The ID of the application which was allocated on creation, and can be used for delete calls. # Syntax diff --git a/website/docs/r/mqcloud_keystore_certificate.html.markdown b/website/docs/r/mqcloud_keystore_certificate.html.markdown index dcdf7050db..3ddceaeae4 100644 --- a/website/docs/r/mqcloud_keystore_certificate.html.markdown +++ b/website/docs/r/mqcloud_keystore_certificate.html.markdown @@ -3,14 +3,14 @@ layout: "ibm" page_title: "IBM : ibm_mqcloud_keystore_certificate" description: |- Manages mqcloud_keystore_certificate. -subcategory: "MQ on Cloud" +subcategory: "MQaaS" --- # ibm_mqcloud_keystore_certificate Create, update, and delete mqcloud_keystore_certificates with this resource. -> **Note:** The MQ on Cloud Terraform provider access is restricted to users of the reserved deployment plan. +> **Note:** The MQaaS Terraform provider access is restricted to users of the reserved deployment, reserved capacity, and reserved capacity subscription plans. ## Example Usage @@ -20,7 +20,6 @@ resource "ibm_mqcloud_keystore_certificate" "mqcloud_keystore_certificate_instan label = "certlabel" queue_manager_id = var.queue_manager_id service_instance_guid = var.service_instance_guid - config { ams { channels { @@ -41,7 +40,7 @@ You can specify the following arguments for this resource. * 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. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQaaS 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 @@ -85,7 +84,7 @@ The `id` property can be formed from `service_instance_guid`, `queue_manager_id`
 <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. +* `service_instance_guid`: A string in the format `a2b4d4bc-dadb-4637-bcec-9b7d1e723af8`. The GUID that uniquely identifies the MQaaS 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. diff --git a/website/docs/r/mqcloud_queue_manager.html.markdown b/website/docs/r/mqcloud_queue_manager.html.markdown index 21cd1f3c97..e9b613f88d 100644 --- a/website/docs/r/mqcloud_queue_manager.html.markdown +++ b/website/docs/r/mqcloud_queue_manager.html.markdown @@ -3,15 +3,14 @@ layout: "ibm" page_title: "IBM : ibm_mqcloud_queue_manager" description: |- Manages mqcloud_queue_manager. -subcategory: "MQ on Cloud" +subcategory: "MQaaS" --- - # ibm_mqcloud_queue_manager -Create, update, and delete mqcloud_queue_managers with this resource. +Create, update, and delete mqcloud_queue_managers with this resource. -> **Note:** The MQ on Cloud Terraform provider access is restricted to users of the reserved deployment plan. +> **Note:** The MQaaS Terraform provider access is restricted to users of the reserved deployment, reserved capacity, and reserved capacity subscription plans. ## Example Usage @@ -27,7 +26,6 @@ resource "ibm_resource_instance" "mqcloud_deployment" { service = "mqcloud" tags = var.tags } - data "ibm_mqcloud_queue_manager_options" "mqcloud_options" { service_instance_guid = ibm_resource_instance.mqcloud_deployment.guid depends_on = [ @@ -48,6 +46,14 @@ resource "ibm_mqcloud_queue_manager" "mqcloud_queue_manager_instance" { } ``` +## Timeouts + +mqcloud_queue_manager provides the following [Timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) configuration options: + +* `create` - (Default 15 minutes) Used for creating a mqcloud_queue_manager. +* `update` - (Default 5 minutes) Used for updating a mqcloud_queue_manager. +* `delete` - (Default 5 minutes) Used for deleting a mqcloud_queue_manager. + ## Argument Reference You can specify the following arguments for this resource. @@ -55,15 +61,15 @@ 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 location 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-._: ])+$/`. Details of applicable locations can be found from either the use of the `ibm_mqcloud_queue_manager_options` datasource for the resource instance or can be found using the [IBM API for MQ on Cloud](https://cloud.ibm.com/apidocs/mq-on-cloud) and be set as a variable. + * Constraints: The maximum length is `150` characters. The minimum length is `2` characters. The value must match regular expression `/^([^[:ascii:]]|[a-zA-Z0-9-._: ])+$/`. Details of applicable locations can be found from either the use of the `ibm_mqcloud_queue_manager_options` datasource for the resource instance or can be found using the [IBM API for MQaaS](https://cloud.ibm.com/apidocs/mq-on-cloud) and be set as a variable. * `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. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQaaS 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. * Constraints: Allowable values are: `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]+$/`. Details of applicable versions can be found from either the use of the `ibm_mqcloud_queue_manager_options` datasource for the resource instance, can be found using the [IBM API for MQ on Cloud](https://cloud.ibm.com/apidocs/mq-on-cloud) or with the variable not included at all to default to the latest version. + * 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]+$/`. Details of applicable versions can be found from either the use of the `ibm_mqcloud_queue_manager_options` datasource for the resource instance, can be found using the [IBM API for MQaaS](https://cloud.ibm.com/apidocs/mq-on-cloud) or with the variable not included at all to default to the latest version. ## Attribute Reference @@ -90,7 +96,7 @@ The `id` property can be formed from `service_instance_guid`, and `queue_manager
 <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. +* `service_instance_guid`: A string in the format `a2b4d4bc-dadb-4637-bcec-9b7d1e723af8`. The GUID that uniquely identifies the MQaaS 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 diff --git a/website/docs/r/mqcloud_truststore_certificate.html.markdown b/website/docs/r/mqcloud_truststore_certificate.html.markdown index 1fd1cf84e0..e031fed017 100644 --- a/website/docs/r/mqcloud_truststore_certificate.html.markdown +++ b/website/docs/r/mqcloud_truststore_certificate.html.markdown @@ -3,14 +3,14 @@ layout: "ibm" page_title: "IBM : ibm_mqcloud_truststore_certificate" description: |- Manages mqcloud_truststore_certificate. -subcategory: "MQ on Cloud" +subcategory: "MQaaS" --- # ibm_mqcloud_truststore_certificate Create, update, and delete mqcloud_truststore_certificates with this resource. -> **Note:** The MQ on Cloud Terraform provider access is restricted to users of the reserved deployment plan. +> **Note:** The MQaaS Terraform provider access is restricted to users of the reserved deployment, reserved capacity, and reserved capacity subscription plans. ## Example Usage @@ -33,7 +33,7 @@ You can specify the following arguments for this resource. * 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. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQaaS 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 @@ -65,7 +65,7 @@ The `id` property can be formed from `service_instance_guid`, `queue_manager_id`
 <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. +* `service_instance_guid`: A string in the format `a2b4d4bc-dadb-4637-bcec-9b7d1e723af8`. The GUID that uniquely identifies the MQaaS 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. diff --git a/website/docs/r/mqcloud_user.html.markdown b/website/docs/r/mqcloud_user.html.markdown index e5b4a647f0..e12098f817 100644 --- a/website/docs/r/mqcloud_user.html.markdown +++ b/website/docs/r/mqcloud_user.html.markdown @@ -3,14 +3,14 @@ layout: "ibm" page_title: "IBM : ibm_mqcloud_user" description: |- Manages mqcloud_user. -subcategory: "MQ on Cloud" +subcategory: "MQaaS" --- # ibm_mqcloud_user Create, update, and delete mqcloud_users with this resource. -> **Note:** The MQ on Cloud Terraform provider access is restricted to users of the reserved deployment plan. +> **Note:** The MQaaS Terraform provider access is restricted to users of the reserved deployment, reserved capacity, and reserved capacity subscription plans. ## Example Usage @@ -30,7 +30,7 @@ You can specify the following arguments for this resource. * 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. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQaaS 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 @@ -50,7 +50,7 @@ The `id` property can be formed from `service_instance_guid`, and `user_id` in t
 <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. +* `service_instance_guid`: A string in the format `a2b4d4bc-dadb-4637-bcec-9b7d1e723af8`. The GUID that uniquely identifies the MQaaS service instance. * `user_id`: A string. The ID of the user which was allocated on creation, and can be used for delete calls. # Syntax diff --git a/website/docs/r/mqcloud_virtual_private_endpoint_gateway.html.markdown b/website/docs/r/mqcloud_virtual_private_endpoint_gateway.html.markdown new file mode 100644 index 0000000000..85ba40423c --- /dev/null +++ b/website/docs/r/mqcloud_virtual_private_endpoint_gateway.html.markdown @@ -0,0 +1,66 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_mqcloud_virtual_private_endpoint_gateway" +description: |- + Manages mqcloud_virtual_private_endpoint_gateway. +subcategory: "MQaaS" +--- + +# ibm_mqcloud_virtual_private_endpoint_gateway + +Create, update, and delete mqcloud_virtual_private_endpoint_gateways with this resource. + +> **Note:** The MQaaS Terraform provider access is restricted to users of the reserved deployment, reserved capacity, and reserved capacity subscription plans. + +## Example Usage + +```hcl +resource "ibm_mqcloud_virtual_private_endpoint_gateway" "mqcloud_virtual_private_endpoint_gateway_instance" { + name = "vpe_gateway1-to-vpe_gateway2" + service_instance_guid = "a2b4d4bc-dadb-4637-bcec-9b7d1e723af8" + target_crn = "crn:v1:staging:public:mq-eude-stackname:eu-de:::endpoint:qm1.private.stackname.mq2.test.appdomain.cloud" + trusted_profile = "crn:v1:staging:public:mq-eude-stackname:eu-de:::endpoint:qm1.private.stackname.mq2.test.appdomain.cloud" +} +``` + +## Argument Reference + +You can specify the following arguments for this resource. + +* `name` - (Required, Forces new resource, String) The name of the virtual private endpoint gateway, created by the user. + * Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z]|[a-z][-a-z0-9]*[a-z0-9]$/`. +* `service_instance_guid` - (Required, Forces new resource, String) The GUID that uniquely identifies the MQaaS 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}$/`. +* `target_crn` - (Required, Forces new resource, String) The CRN of the reserved capacity service instance the user is trying to connect to. + * Constraints: The maximum length is `512` characters. The minimum length is `9` characters. The value must match regular expression `/^crn:v[0-9]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]*:([a-z]\/[a-z0-9-]+)?:[a-z0-9-]*:[a-z0-9-]*:[a-zA-Z0-9-_\\.\/]*$|^crn:\\[\\.\\.\\.\\]$/`. +* `trusted_profile` - (Optional, Forces new resource, String) The CRN of the trusted profile to assume for this request. + * Constraints: The maximum length is `512` characters. The minimum length is `9` characters. The value must match regular expression `/^crn:v[0-9]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]*:([a-z]\/[a-z0-9-]+)?:[a-z0-9-]*:[a-z0-9-]*:[a-zA-Z0-9-_\\.\/]*$|^crn:\\[\\.\\.\\.\\]$/`. + +## 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_virtual_private_endpoint_gateway. +* `href` - (String) URL for the details of the virtual private endpoint gateway. + * Constraints: The maximum length is `8000` characters. The minimum length is `10` characters. The value must match regular expression `/^http(s)?:\/\/([^\/?#]*)([^?#]*)(\\?([^#]*))?(#(.*))?$/`. +* `status` - (String) The lifecycle state of this virtual privage endpoint. + * Constraints: The maximum length is `12` characters. The minimum length is `2` characters. The value must match regular expression `/^deleting$|failed$|pending$|stable$|suspended$|updating$|waiting$/`. +* `virtual_private_endpoint_gateway_guid` - (String) The ID of the virtual private endpoint gateway which was allocated on creation. + * Constraints: The maximum length is `41` characters. The minimum length is `41` characters. The value must match regular expression `/^[0-9a-zA-Z]{4}-[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}$/`. + + +## Import + +You can import the `ibm_mqcloud_virtual_private_endpoint_gateway` resource by using `id`. +The `id` property can be formed from `service_instance_guid`, and `virtual_private_endpoint_gateway_guid` in the following format: + +
+<service_instance_guid>/<virtual_private_endpoint_gateway_guid>
+
+* `service_instance_guid`: A string in the format `a2b4d4bc-dadb-4637-bcec-9b7d1e723af8`. The GUID that uniquely identifies the MQaaS service instance. +* `virtual_private_endpoint_gateway_guid`: A string. The ID of the virtual private endpoint gateway which was allocated on creation. + +# Syntax +
+$ terraform import ibm_mqcloud_virtual_private_endpoint_gateway.mqcloud_virtual_private_endpoint_gateway <service_instance_guid>/<virtual_private_endpoint_gateway_guid>
+
diff --git a/website/docs/r/pag_instance.html.markdown b/website/docs/r/pag_instance.html.markdown index 6312556868..ee9bd57c97 100644 --- a/website/docs/r/pag_instance.html.markdown +++ b/website/docs/r/pag_instance.html.markdown @@ -144,8 +144,8 @@ The `ibm_resource_instance` resource provides the following [Timeouts](https://w ## Argument reference Review the argument references that you can specify for your resource. -- `location` - (Required, String) Target location or environment to create the PAG instance. -- `parameters_json` - (Required, String) Parameters to create PAG instance. The value must be a JSON string. +- `location` - (Required, Forces new resource, String) Target location or environment to create the PAG instance. +- `parameters_json` - (Required, Forces new resource, String) Parameters to create PAG instance. The value must be a JSON string. Nested scheme for `parameters_json`: - `cosinstance` - (Required, String) COS instance CRN to use for PAG. diff --git a/website/docs/r/pi_capture.html.markdown b/website/docs/r/pi_capture.html.markdown index 1ed656619f..7d61848b5f 100644 --- a/website/docs/r/pi_capture.html.markdown +++ b/website/docs/r/pi_capture.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_capture" @@ -8,40 +7,46 @@ description: |- --- # ibm_pi_capture + Create or delete for Capture Power System Virtual Server Instance **Note:-** If `pi_capture_destination` is `Cloud-Storage` then delete bucket object functionality not supported by this resource , hence user need to delete bucket object manually from `Cloud Storage bucket`. For more information, about IBM power virtual server cloud, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). + ## Example usage + The following example creates a Capture Power System Virtual Server Instance. ```terraform resource "ibm_pi_capture" "test_capture" { - pi_cloud_instance_id = "49fba6c9-23f8-40bc-9899-aca322ee7d5b" - pi_capture_name = "terraform-test-capture" - pi_instance_name = "terraform-test-instance" - pi_capture_destination = "image-catalog" + pi_cloud_instance_id = "49fba6c9-23f8-40bc-9899-aca322ee7d5b" + pi_capture_name = "terraform-test-capture" + pi_instance_name = "terraform-test-instance" + pi_capture_destination = "image-catalog" } ``` + ```terraform resource "ibm_pi_capture" "test_capture" { - pi_cloud_instance_id = "49fba6c9-23f8-40bc-9899-aca322ee7d5b" - pi_capture_name = "test-capture" - pi_instance_name = "test-vm" - pi_capture_destination = "cloud-storage" - pi_capture_cloud_storage_region = "us-east" - pi_capture_cloud_storage_access_key = "" - pi_capture_cloud_storage_secret_key = "" - pi_capture_storage_image_path = "test-bucket" + pi_cloud_instance_id = "49fba6c9-23f8-40bc-9899-aca322ee7d5b" + pi_capture_name = "test-capture" + pi_instance_name = "test-vm" + pi_capture_destination = "cloud-storage" + pi_capture_cloud_storage_region = "us-east" + pi_capture_cloud_storage_access_key = "" + pi_capture_cloud_storage_secret_key = "" + pi_capture_storage_image_path = "test-bucket" } ``` -**Note** -* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. -* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: - * `region` - `lon` - * `zone` - `lon04` + +### Notes + +- Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +- If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + - `region` - `lon` + - `zone` - `lon04` Example usage: @@ -51,15 +56,17 @@ resource "ibm_pi_capture" "test_capture" { zone = "lon04" } ``` + ## Timeouts ibm_pi_capture provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: -- **create** - (Default 75 minutes) Used for creating capture instance . +- **create** - (Default 75 minutes) Used for creating capture instance. - **delete** - (Default 50 minutes) Used for deleting capture instance. -## Argument reference -Review the argument references that you can specify for your resource. +## Argument reference + +Review the argument references that you can specify for your resource. - `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. - `pi_capture_name` - (Required, String) Name of the deployable image created for the captured PVMInstance. @@ -67,27 +74,26 @@ Review the argument references that you can specify for your resource. - `pi_capture_destination`- (Required, String) Destination for the deployable image. `[image-catalog,cloud-storage,both]` - `pi_capture_volume_ids`- (Optional, List of String) List of Data volume IDs to include in the captured PVMInstance. -- `pi_capture_cloud_storage_region`- (Optional,String) The Cloud Object Storage region. Supported COS regions are: `au-syd`, `br-sao`, `ca-tor`, `eu-de`, `eu-es`, `eu-gb`, `jp-osa`, `jp-tok`, `us-east`, `us-south`. +- `pi_capture_cloud_storage_region`- (Optional,String) The Cloud Object Storage region. Supported COS regions are: `au-syd`, `br-sao`, `ca-tor`, `che01`, `eu-de`, `eu-es`, `eu-gb`, `jp-osa`, `jp-tok`, `us-east`, `us-south`. - `pi_capture_cloud_storage_access_key`- (Optional,String) Cloud Storage Access key - `pi_capture_cloud_storage_secret_key`- (Optional,String) Cloud Storage Secret key - `pi_capture_storage_image_path` - (Optional,String) Cloud Storage Image Path (bucket-name [/folder/../..]) - `pi_user_tags` - (Optional, List) List of user tags attached to the resource. ## Attribute reference + In addition to all argument reference list, you can access the following attribute reference after your resource is created. - `crn` - (String) The CRN of the resource. - `id` - (String) The image id of the capture instance. The ID is composed of `//`. - `image_id` - (String) The image id of the capture instance. - ## Import The `ibm_pi_capture` resource can be imported by using `pi_cloud_instance_id` `pi_capture_name` and `pi_capture_destination`. -**Example** -``` -$ terraform import ibm_pi_capture.example d7bec597-4726-451f-8a63-e62e6f19c32c/test-capture/image-catalog +### Example +```bash +terraform import ibm_pi_capture.example d7bec597-4726-451f-8a63-e62e6f19c32c/test-capture/image-catalog ``` - diff --git a/website/docs/r/pi_image.html.markdown b/website/docs/r/pi_image.html.markdown index c65d404edd..db83f6b940 100644 --- a/website/docs/r/pi_image.html.markdown +++ b/website/docs/r/pi_image.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_image" @@ -83,7 +82,7 @@ Review the argument references that you can specify for your resource. - `pi_image_bucket_access` - (Optional, String) Indicates if the bucket has public or private access. The default value is `public`. - `pi_image_bucket_file_name` - (Optional, String) Cloud Object Storage image filename - `pi_image_bucket_file_name` is required with `pi_image_bucket_name` -- `pi_image_bucket_region` - (Optional, String) Cloud Object Storage region. Supported COS regions are: `au-syd`, `br-sao`, `ca-tor`, `eu-de`, `eu-es`, `eu-gb`, `jp-osa`, `jp-tok`, `us-east`, `us-south`. +- `pi_image_bucket_region` - (Optional, String) Cloud Object Storage region. Supported COS regions are: `au-syd`, `br-sao`, `ca-tor`, `che01`, `eu-de`, `eu-es`, `eu-gb`, `jp-osa`, `jp-tok`, `us-east`, `us-south`. - `pi_image_bucket_region` is required with `pi_image_bucket_name` - `pi_image_secret_key` - (Optional, String, Sensitive) Cloud Object Storage secret key; required for buckets with private access. - `pi_image_secret_key` is required with `pi_image_access_key` diff --git a/website/docs/r/pi_image_export.html.markdown b/website/docs/r/pi_image_export.html.markdown index 1b1e71fe6e..2bb90e2517 100644 --- a/website/docs/r/pi_image_export.html.markdown +++ b/website/docs/r/pi_image_export.html.markdown @@ -1,5 +1,4 @@ --- - subcategory: "Power Systems" layout: "ibm" page_title: "IBM: pi_image_export" @@ -8,30 +7,33 @@ description: |- --- # ibm_pi_image_export + Export an image to IBM Cloud Object Storage for Power Systems Virtual Server instance. For more information, about IBM power virtual server cloud, see [getting started with IBM Power Systems Virtual Servers](https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-getting-started). ## Example usage + The following example enables you to export an image: ```terraform resource "ibm_pi_image_export" "testacc_image_export"{ - pi_cloud_instance_id = "" - pi_image_id = "test_image" - pi_image_bucket_name = "images-public-bucket" + pi_cloud_instance_id = "" + pi_image_id = "test_image" + pi_image_access_key = "dummy-access-key" + pi_image_bucket_name = "images-public-bucket" pi_image_bucket_region = "us-south" - pi_image_access_key = "dummy-access-key" - pi_image_secret_key = "dummy-secret-key" + pi_image_secret_key = "dummy-secret-key" } ``` -**Note** -* Ensure the exported file is cleaned up manually from the Cloud Object Storage when no longer needed. Power Systems Virtual Server does not support deleting the exported image. Updating any attribute will result in creating a new Export job. -* Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. -* If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: - * `region` - `lon` - * `zone` - `lon04` +### Notes + +- Ensure the exported file is cleaned up manually from the Cloud Object Storage when no longer needed. Power Systems Virtual Server does not support deleting the exported image. Updating any attribute will result in creating a new Export job. +- Please find [supported Regions](https://cloud.ibm.com/apidocs/power-cloud#endpoint) for endpoints. +- If a Power cloud instance is provisioned at `lon04`, The provider level attributes should be as follows: + - `region` - `lon` + - `zone` - `lon04` - Example usage: +Example usage: ```terraform provider "ibm" { @@ -44,22 +46,21 @@ resource "ibm_pi_image_export" "testacc_image_export"{ The ibm_pi_image provides the following [timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: -- **Create** The export image to IBM Cloud Object Storage bucket is considered failed if no response is received for 60 minutes. +- **create** The export image to IBM Cloud Object Storage bucket is considered failed if no response is received for 60 minutes. ## Argument reference -Review the argument references that you can specify for your resource. + +Review the argument references that you can specify for your resource. - `pi_cloud_instance_id` - (Required, String) The GUID of the service instance associated with an account. - `pi_image_id` - (Required, String) The Image ID of existing source image; required for image export. - `pi_image_bucket_name` - (Required, String) The Cloud Object Storage bucket name; `bucket-name[/optional/folder]` - `pi_image_access_key` - (Required, String, Sensitive) The Cloud Object Storage access key; required for buckets with private access. -- `pi_image_bucket_region` - (Required, String) The Cloud Object Storage region. Supported COS regions are:`au-syd`, `br-sao`, `ca-tor`, `eu-de`, `eu-es`, `eu-gb`, `jp-osa`, `jp-tok`, `us-east`, `us-south`. +- `pi_image_bucket_region` - (Required, String) The Cloud Object Storage region. Supported COS regions are:`au-syd`, `br-sao`, `ca-tor`, `che01`, `eu-de`, `eu-es`, `eu-gb`, `jp-osa`, `jp-tok`, `us-east`, `us-south`. - `pi_image_secret_key` - (Required, String, Sensitive) The Cloud Object Storage secret key; required for buckets with private access. - - ## Attribute reference + In addition to all argument reference list, you can access the following attribute reference after your resource is created. - `id` - (String) The unique identifier of an image export resource. The ID is composed of `//`. - diff --git a/website/docs/r/pi_network.html.markdown b/website/docs/r/pi_network.html.markdown index e8ece20e93..e2ddbd8c0f 100644 --- a/website/docs/r/pi_network.html.markdown +++ b/website/docs/r/pi_network.html.markdown @@ -71,7 +71,16 @@ Review the argument references that you can specify for your resource. - `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` - (Deprecated, Optional, Bool) MTU Jumbo option of the network (for multi-zone locations only). - `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). +- `pi_network_access_config` - (Deprecated, Optional, String) The network communication configuration option of the network (for on-prem locations only). Please use `pi_network_peer`. +- `pi_network_peer` - (Optional, List) Network peer information (for on-prem locations only). Max items: 1. + + Nested schema for `pi_network_peer`: + - `id` - (Required, String) ID of the network peer. + - `network_address_translation` - (Optional, List) Contains the Network Address Translation Details. Max items: 1. + + Nested schema for `network_address_translation`: + - `source_ip` - (Optional, String) source IP address, required if network peer type is `L3BGP` or `L3STATIC` and if NAT is enabled. + - `type` - (Optional, String) Type of the network peer. Allowable values are: `L2`, `L3BGP`, `L3Static`. - `pi_user_tags` - (Optional, List) The user tags attached to this resource. ## Attribute reference @@ -81,6 +90,11 @@ In addition to all argument reference list, you can access the following attribu - `crn` - (String) The CRN of this resource. - `id` - (String) The unique identifier of the network. The ID is composed of `/`. - `network_id` - (String) The unique identifier of the network. +- `network_address_translation` - (List) Contains the network address translation details (for on-prem locations only). + + Nested schema for `network_address_translation`: + - `source_ip` - (String) source IP address. +- `peer_id` - (String) Network peer ID (for on-prem locations only). - `vlan_id` - (Integer) The ID of the VLAN that your network is attached to. ## Import diff --git a/website/docs/r/resource_instance.html.markdown b/website/docs/r/resource_instance.html.markdown index 234f336a8f..50bc6eb113 100644 --- a/website/docs/r/resource_instance.html.markdown +++ b/website/docs/r/resource_instance.html.markdown @@ -20,7 +20,7 @@ data "ibm_resource_group" "group" { resource "ibm_resource_instance" "resource_instance" { name = "test" service = "cloud-object-storage" - plan = "lite" + plan = "standard" location = "global" resource_group_id = data.ibm_resource_group.group.id tags = ["tag1", "tag2"] diff --git a/website/docs/r/scc_instance_settings.html.markdown b/website/docs/r/scc_instance_settings.html.markdown index 35f6fc9a91..0bbfad4555 100644 --- a/website/docs/r/scc_instance_settings.html.markdown +++ b/website/docs/r/scc_instance_settings.html.markdown @@ -39,6 +39,8 @@ Nested schema for **event_notifications**: * `source_id` - (Computed, String) The connected Security and Compliance Center instance CRN. * Constraints: The maximum length is `512` characters. The minimum length is `1` character. The value must match regular expression `/([A-Za-z0-9]+(:[A-Za-z0-9]+)+)/`. * `updated_on` - (Optional, String) The date when the Event Notifications connection was updated. + * `source_description` - (Optional,Computed, String) The description of the Event Notifications connection source. + * `source_name` - (Optional,Computed, String) The name of the Event Notifications connection source. * `object_storage` - (Optional, List) The Cloud Object Storage settings. Nested schema for **object_storage**: * `bucket` - (Optional, String) The connected Cloud Object Storage bucket name. @@ -69,4 +71,4 @@ $ terraform import ibm_scc_instance_settings.scc_instance_settings # Example ```bash $ terraform import ibm_scc_instance_settings.scc_instance_settings 00000000-1111-2222-3333-444444444444 -``` \ No newline at end of file +```